Sections

Abstract

Previously, I sent around some images comparing the alpha diversity results of each run. This met with general approval as well as questions including gamma diversity, the burstiness of arrivals (co-establishment), the burstiness of extinctions (co-extinctions), and comparisons with purely neutral models of arrival and extinction.

In this document, we continue to attempt to address Chris’s question of how increased spatial mobility changes biodiversity measures. We begin by loading up each data set referring to different neutral (arrival-extinction) and spatial (dispersal speed) conditions. We can then extract our diversity metrics for each system and each site/ecosystem/environment within the system and compare them.

Notes

  • While Chris prefers abundance/richness as a dichotomy, it might be helpful for publication to consider more than that.

TODO

  • Measure the impact of dispersal on invadability. This preferably identifies both the height of the new barrier as well as precisely determining the effect. This might include the asymmetry at the ends of the line spatial arrangement (as compared to a ring spatial arrangement). ** I anticipate that this is precisely the effect of the extra term. To show it then, analytically we can check the per-capita rate of growth with the additional term, which will act as a penalty. Empirically, we look at the invasions that we expect to have succeeded but then died out when space was introduced and we should be able to see a good match between its predicted per-capita growth rate and when/if it died out within a given system. This breaks down if it can survive in an adjacent system, for what it is worth.
  • Evenness by trophic level. This might help us deduce how neutral the trophic levels are, but requires analysing how the trophic network changes over time (possibly in contrast to the theoretical food web). Furthermore, this is most advantageous to investigate as we change the parameters of the simulation to include more trophic levels. This would also allow us to color code abundance and examine richness of trophic levels (both number of levels and richness within levels). ** We should make a point of running another layer of consumers (and producers?) as well so as to be able to better observe the resultant diversity. I do note that, contrary to previous expecations, we are running at about \(30\%\) of the pool. As I am only using 1 pool at this point, there might be a high amount of variation. ** The parent point here might require moving onto Viking. The deSolve package does have functions that return lists, where the first element is a vector of derivatives of \(y\) with respect to \(t\). The ‘’next’’ elements seem like they could be things like the trophic structure and trophic levels.
  • We should consider the “run to stability”, then variable change. This requires another set of (2 sets of) systems where we run the system as before to stability (everything looks stable at least!) and then make a jump in one (or two? space and arrival or space and extinction rate?) of the parameters.
  • From previous chats, there is also the prospect of comparing ‘’pure’’ neutral dynamics. In terms of simulations, a pool of the same size, but all producers would seem to do it. In terms of analytics, there should be a good neutral theory solution.
  • Another point of interest is how bursty is the distribution compared to the exponential null model? This in effect studies the impact of the dynamics. If they are far burstier than we expect/neutrality would dictate, than we can deduce there are multiple related secondary extinctions. Otherwise, the system would appear to be merely neutral dynamics and primary extinctions.

Future

  • Once the strictly deterministic dynamics are sufficiently cleared out, Chris (and Susan) would like to swap to Gillespie style / jump process / stochiometry dynamics.

Functions

library(dplyr)        # Data Manipulation
library(tidyr)        # Data Pivotting
library(ggplot2)      # 2-D Plot
library(plotly)       # 3-D Plot
library(ggfortify)    # used for biplots of PCAs
library(vegan)        # Ecological analysis mega-package
library(htmltools)    # Programmatic chunks
library(fitdistrplus) # Advanced fitting over MASS.
library(poweRlaw)     # Fitting heavy-tailed distributions.
library(RMTRCode2)    # Personal package.
# https://stackoverflow.com/a/7172832
ifrm <- function(obj, env = globalenv()) {
  obj <- deparse(substitute(obj))
  if(exists(obj, envir = env)) {
    rm(list = obj, envir = env)
  }
}
log0 <- function(x, base = exp(1)) {
  xneq0 <- x != 0 & !is.na(x)
  x[xneq0] <- log(x[xneq0], base = base)
  return(x)
}

Data

As of the writing of this script, all of the data is stored in the same location as this script. The parameters used to generate the interaction matrices, pools, and events is not stored with the attempts, which is something I should probably fix in the future. (I could store them in the ellipsis argument or as a separate object.)

by_for_thinning <- 10 # time steps
divide_time_by <- 1E4 # time units
burn_in <- 1E4 # time units
load_safe_thin <- function(fname, bythin, divtime, burn) {
  loaded <- tryCatch({load(fname)}, 
                     error = function(e) {
                       print(fname)
                       print(e)
                       return(NA)
                     })
  if (is.na(loaded)) {
    return(NA)
  } else {
    loaded <- get(loaded)
    loaded$Abundance <- loaded$Abundance[seq(from = 1,
                                             to = nrow(loaded$Abundance),
                                             by = bythin), ]
    
    toEliminate <- loaded$Abundance[, -1] < loaded$Parameters$EliminationThreshold & loaded$Abundance[, -1] > 0
    loaded$Abundance[, -1][toEliminate] <- 0
    
    loaded$Abundance <- loaded$Abundance[
      loaded$Abundance[, 1] > burn,
    ]
    
    loaded$Abundance[, 1] <- loaded$Abundance[, 1] / divtime
    return(loaded)
  }
}
# All .RData
files_dat <- dir(pattern = ".RData$")
# Remove PoolMats
files_dat <- files_dat[
  !grepl(x = files_dat, 
         pattern = "PoolMats", 
         fixed = TRUE)
  ]
# Technically overkill, but prevents unintentional loads.
# Break into two separate runs to load only intended.
# Process "MNA-FirstAttempt#####-Result-Env10-####.RData"
files_dat_FA <- files_dat[
  grepl(x = files_dat, 
        pattern = "FirstAttempt", 
        fixed = TRUE)
  ]
Results <- sapply(
  files_dat_FA,
  load_safe_thin, 
  bythin = by_for_thinning,
  divtime = divide_time_by, 
  burn = burn_in,
  simplify = FALSE, USE.NAMES = TRUE
)
# Process "MNA-Dist#####-Ext###-Env10-####.RData"
files_dat_Ext <- files_dat[
  grepl(x = files_dat, 
        pattern = "Dist", 
        fixed = TRUE)
  ]
Results <- c(Results, sapply(
  files_dat_Ext,
  load_safe_thin, 
  bythin = by_for_thinning, 
  divtime = divide_time_by, 
  burn = burn_in,
  simplify = FALSE, USE.NAMES = TRUE
))

Pools and Matrices

load_safe <- function(fname) {
  loaded <- tryCatch({load(fname)}, 
                     error = function(e) {
                       print(fname)
                       print(e)
                       return(NA)
                     })
  if (all(is.na(loaded))) {
    return(NA)
  } else {
    return(sapply(loaded, get, 
                  envir = sys.frame(sys.parent(0)), 
                  simplify = FALSE, USE.NAMES = TRUE))
  }
}
# All .RData
files_dat_PM <- dir(pattern = ".RData$")
# Remove PoolMats
files_dat_PM <- files_dat_PM[
  grepl(x = files_dat_PM, 
        pattern = "PoolMats", 
        fixed = TRUE)
  ]
PoolsMats <- sapply(
  files_dat_PM,
  load_safe, 
  simplify = FALSE, USE.NAMES = TRUE
)

Trophic Functions

EliminiationThreshold <- unique(sapply(
  Results, 
  function(lst) {lst$Parameters$EliminationThreshold}
))
stopifnot(length(EliminiationThreshold) == 1)
NumEnvironments <- unique(sapply(
  Results, 
  function(lst) {lst$NumEnvironments}
))
stopifnot(length(NumEnvironments) == 1)
TrophicFunctions <- sapply(
  PoolsMats,
  function(PM, NE, ET) {
    RMTRCode2::CalculateTrophicStructure(
      Pool = PM$Pool,
      NumEnvironments = NE,
      InteractionMatrices = PM$InteractionMatrices,
      EliminationThreshold = ET
    )
  },
  NE = NumEnvironments,
  ET = EliminiationThreshold
)
#TODO Fix warning (binding character and factor vector, coercing into character vector in bind_rows)
TrophicAnalyses <- list()
Result = Results
Nm = names(Results)
TrophFN = TrophicFunctions

for (i in seq_along(Results)) {
  print(i); print(Nm[i])
  # Identify Appropriate Function.
  Unusual1 <- grepl(pattern = "FirstAttempt",
                    x = Nm[i], fixed = TRUE)
  NormalKey <- strsplit(Nm[i], split = '-')[[1]][3]
  linkedFN <- if(Unusual1) {
    TrophFN[grepl(x = names(TrophFN),
                  pattern = "FirstAttempt", fixed = TRUE)][[1]]
  } else {
    TrophFN[grepl(x = names(TrophFN),
                  pattern = NormalKey, fixed = TRUE)][[1]]
  }
  
  # Apply to each row.
  
  TrophicAnalyses[[i]] <- apply(Result[[i]]$Abundance[, -1],
                                MARGIN = 1,
                                FUN = linkedFN)
}

# TrophicAnalyses <- lapply(
#   seq_along(Results),
#   function(i, Result, Nm, TrophFN) {
#     # Identify Appropriate Function.
#     Unusual1 <- grepl(pattern = "FirstAttempt",
#                       x = Nm[i], fixed = TRUE)
#     NormalKey <- strsplit(Nm[i], split = '-')[[1]][3]
#     linkedFN <- if(Unusual1) {
#       TrophFN[grepl(x = names(TrophFN),
#                      pattern = "FirstAttempt", fixed = TRUE)][[1]]
#     } else {
#       TrophFN[grepl(x = names(TrophFN), 
#                      pattern = NormalKey, fixed = TRUE)][[1]]
#     }
#     
#     # Apply to each row.
#     
#     return(apply(Result[[i]]$Abundance[, -1],
#                  MARGIN = 1,
#                  FUN = linkedFN)
#     )
#   },
#   Result = Results,
#   Nm = names(Results),
#   TrophFN = TrophicFunctions
# )

names(TrophicAnalyses) <- names(Results)

Diversity

Preparation

# Borrowing code from FirstAttempt-Doc-Analysis.Rmd
Calculate_Diversity <- function(result) {
  Diversity <- lapply(
    1:result$NumEnvironments,
    function(i, abund, numSpecies) {
      time <- abund[, 1]
      env <- abund[, 1 + 1:numSpecies + numSpecies * (i - 1)]
      richness <- rowSums(env != 0)
      abundSum <- rowSums(env)
      #NOTE: THIS CAN YIELD NAN'S (0/0).
      # THIS IS NOT NECESSARILY A PROBLEM.
      # IT MIGHT BE WORTH IT JUST TO USE 0 OR
      # TO CATCH IT EXPLICITLY AND REPLACE WITH NAN.
      entropy <- env / abundSum
      entropy <- - apply(
        entropy, MARGIN = 1,
        FUN = function(x) {
          sum(x * log0(x))
        })
      species <- apply(
        env, MARGIN = 1,
        FUN = function(x) {
          toString(which(x > 0))
        }
      )
      evenness <- entropy / log(richness)
      data.frame(Time = time, 
                 Richness = richness, 
                 Entropy = entropy,
                 Evenness = evenness,
                 Species = species,
                 Environment = i,
                 stringsAsFactors = FALSE)
    },
    abund = result$Abundance,
    numSpecies = (ncol(result$Abundance) - 1) / result$NumEnvironments
  )
  
  
  Diversity <- dplyr::bind_rows(Diversity)
  Diversity_alpha <- Diversity
  # Diversity_alpha <- Diversity_alpha %>% dplyr::mutate(
  #   Evenness = Entropy / log(Richness)
  # )
  
  # Modify to do the gamma bits right here.
  Diversity_gamma <- Diversity %>% dplyr::group_by(
    Time
  ) %>% dplyr::summarise(
    Mean = mean(Richness),
    SpeciesTotal = toString(sort(unique(unlist(strsplit(paste(
      Species, collapse = ", "), split = ", ", fixed = TRUE))))),
    Gamma = unlist(lapply(strsplit(
      SpeciesTotal, split = ", ", fixed = TRUE), function(x) length(x[x!=""]) ))
  ) %>% tidyr::pivot_longer(
    cols = c(Mean, Gamma), 
    names_to = "Aggregation",
    values_to = "Richness"
  )
  
  # Combine the two types of results
  Diversity_alpha <- Diversity_alpha %>% dplyr::select(
    -Species
  ) %>% tidyr::pivot_longer(
    cols = c(Richness, Entropy, Evenness),
    names_to = "Measurement",
    values_to = "Value"
  ) %>% dplyr::mutate(
    Environment = as.character(Environment)
  )
  
  Diversity_gamma <- Diversity_gamma %>% dplyr::select(
    -SpeciesTotal
  ) %>% dplyr::rename(
    Environment = Aggregation,
    Value = Richness
  ) %>% dplyr::mutate(
    Measurement = "Richness"
  )
  
  Diversity_beta <- Diversity_alpha %>% dplyr::filter(
    Measurement == "Richness"
  ) %>% dplyr::select(
    -Measurement
  ) %>% dplyr::left_join(
    y = Diversity_gamma %>% dplyr::filter(
      Measurement == "Richness", Environment == "Gamma"
    ) %>% dplyr::select(
      -Measurement, -Environment
    ),
    by = "Time",
    suffix = c("_Alpha", "_Gamma")
    # ) %>% dplyr::group_by(
    #   Time
  ) %>% dplyr::mutate(
    BetaSpeciesMissing = Value_Gamma - Value_Alpha,
    BetaSpeciesPercentage = Value_Alpha/Value_Gamma
  ) %>% dplyr::select(
    -Value_Gamma, -Value_Alpha
  ) %>% tidyr::pivot_longer(
    names_to = "Measurement",
    values_to = "Value",
    cols = c(BetaSpeciesMissing, BetaSpeciesPercentage)
    # ) %>% dplyr::ungroup(
  )
  
  #print(c(colnames(Diversity_alpha), colnames(Diversity_beta), colnames(Diversity_gamma)))
  Diversity <- rbind(
    Diversity_alpha,
    Diversity_beta,
    Diversity_gamma
  )
  
  return(Diversity)
}
Diversity_jaccard_space <- function(result) {
  apply(
    result$Abundance,
    MARGIN = 1, # Rows
    function(row, envs) {
      time <- row[1]
      dists <- vegan::vegdist(
        method = "jaccard", 
        x = matrix(row[-1] > 0, nrow = envs, byrow = TRUE)
      )
      
      dataf <- expand.grid(
        Env1 = 1:envs,
        Env2 = 1:envs
      ) %>% dplyr::filter(
        Env1 < Env2
      ) %>% dplyr::mutate(
        Time = time,
        Jaccard = dists
      )
      
      return(dataf)
    },
    envs = result$NumEnvironments
  )
}
Diversity_jaccard_time <- function(result, subsample = 100) {
  # Break into environments, then apply it to the time series.
  patches <- lapply(
    1:result$NumEnvironments, function(i, abund, envs, spec) {
      abund <- abund[seq(from = 1, to = nrow(abund), by = subsample), ]
      times <- abund[, 1]
      patch <- abund[, 1 + 1:spec + spec * (i - 1)]
      
      dists <- vegan::vegdist(
        method = "jaccard", 
        x = patch > 0
      )
      
      dataf <- expand.grid(
        Time1 = times,
        Time2 = times
      ) %>% dplyr::filter(
        Time1 < Time2
      ) %>% dplyr::mutate(
        Environment = i,
        Jaccard = dists
      )
      
      return(dataf)
    }, abund = result$Abundance, envs = result$NumEnvironments,
    spec = (ncol(result$Abundance) - 1) / result$NumEnvironments
  )
}
Calculate_Species <- function(result, bintimes = FALSE) {
  SpeciesPerEnvironment <- lapply(
    1:result$NumEnvironments,
    function(i, abund, numSpecies) {
      time <- abund[, 1]
      env <- abund[, 1 + 1:numSpecies + numSpecies * (i - 1)]
      # Need to retrieve Position and Value
      species <- apply(
        cbind(time, env), MARGIN = 1,
        FUN = function(x) {
          time <- x[1]
          dat <- x[-1]
          if (any(dat > 0)) {
            positions <- (which(dat > 0))
            values <- dat[positions]
            data.frame(
              Time = time,
              Species = positions,
              Abundance = values,
              row.names = NULL
            )
          } else {NULL}
          # Returns as list
        }
      )
      return(
        dplyr::bind_rows(species) %>% dplyr::mutate(
          Environment = i
        )
      )
    },
    abund = result$Abundance,
    numSpecies = (ncol(result$Abundance) - 1) / result$NumEnvironments
  )
  
  if (bintimes) {
    # Should equalise time steps.
    SpeciesPerEnvironment <- lapply(
      SpeciesPerEnvironment, function(SPE) {
        SPE %>% dplyr::mutate(
          TimeFloor = floor(Time*10)/10
        ) %>% dplyr::group_by(
          TimeFloor, Species, Environment
        ) %>% dplyr::summarise(
          Abundance = median(Abundance, na.rm = TRUE)
        )
      })
  }
  
  return(dplyr::bind_rows(SpeciesPerEnvironment))
}
# Note that if a file fails to load, we might have NA instead of a result to work with.
Diversity <- sapply(
  USE.NAMES = TRUE, simplify = FALSE,
  Results, function(result) {
    if (length(result) == 1 && is.na(result)) {
      # Problem case.
      return(NA)
    }
    # print(paste("Calculating", Sys.time()))
    
    # Calculate the diversity.
    # We will need to extract the system properties from
    # the file names which we carry through using sapply.
    return(Calculate_Diversity(result))
  }
)
# Expect warnings since we have all 0 rows on occasion.
JaccardSpace <- sapply(
  USE.NAMES = TRUE, simplify = FALSE,
  Results, function(result) {
    if (length(result) == 1 && is.na(result)) {
      # Problem case.
      return(NA)
    }
    # print(paste("Calculating", Sys.time()))
    
    # Calculate the diversity.
    # We will need to extract the system properties from
    # the file names which we carry through using sapply.
    return(Diversity_jaccard_space(result))
  }
)
# Expect warnings since we have all 0 rows on occasion.
JaccardTime <- sapply(
  USE.NAMES = TRUE, simplify = FALSE,
  Results, function(result) {
    if (length(result) == 1 && is.na(result)) {
      # Problem case.
      return(NA)
    }
    print(paste("Calculating", Sys.time()))
    
    # Calculate the diversity.
    # We will need to extract the system properties from
    # the file names which we carry through using sapply.
    return(Diversity_jaccard_time(result))
    # Too many time points for calculations.
    # Needs to have log(length(times)^2, base = 2) < 31.
    # => length(times) < 46340 or so.
  }
)
[1] "Calculating 2021-11-14 18:47:55"
[1] "Calculating 2021-11-14 18:47:55"
[1] "Calculating 2021-11-14 18:47:55"
[1] "Calculating 2021-11-14 18:47:55"
[1] "Calculating 2021-11-14 18:47:56"
[1] "Calculating 2021-11-14 18:47:56"
[1] "Calculating 2021-11-14 18:47:56"
[1] "Calculating 2021-11-14 18:47:56"
[1] "Calculating 2021-11-14 18:47:56"
[1] "Calculating 2021-11-14 18:47:57"
[1] "Calculating 2021-11-14 18:47:57"
[1] "Calculating 2021-11-14 18:47:57"
[1] "Calculating 2021-11-14 18:47:57"
[1] "Calculating 2021-11-14 18:47:58"
[1] "Calculating 2021-11-14 18:47:59"
[1] "Calculating 2021-11-14 18:47:59"
[1] "Calculating 2021-11-14 18:47:59"
[1] "Calculating 2021-11-14 18:47:59"
[1] "Calculating 2021-11-14 18:48:00"
[1] "Calculating 2021-11-14 18:48:00"
[1] "Calculating 2021-11-14 18:48:01"
[1] "Calculating 2021-11-14 18:48:01"
[1] "Calculating 2021-11-14 18:48:01"
[1] "Calculating 2021-11-14 18:48:01"
[1] "Calculating 2021-11-14 18:48:02"
[1] "Calculating 2021-11-14 18:48:02"
SpeciesPresence <-  sapply(
  USE.NAMES = TRUE, simplify = FALSE,
  Results, function(result) {
    if (length(result) == 1 && is.na(result)) {
      # Problem case.
      return(NA)
    }
    # print(paste("Calculating", Sys.time()))
    
    # Calculate the diversity.
    # We will need to extract the system properties from
    # the file names which we carry through using sapply.
    return(Calculate_Species(result))
  }
)
Properties <- strsplit(names(Diversity), '-', 
                       fixed = TRUE)
# 1st Chunk: Name, Discard
# 2nd Chunk: Iteration + Distance
# 3rd Chunk: Result or Extinction Rate (or Arrival?)
# 4th Chunk: Number of Environments
# 5th Chunk: Space Type + .RData
# Note the mix of Keyword and Location Structure (oops).
# Note also that this strsplit character is a bad decision and should be changed for next time. (D'oh.)
# (E.g. Dates DD-MM-YYYY, Decimals 1.35e-05.)
Properties <- data.frame(
  do.call(rbind, Properties),
  stringsAsFactors = FALSE
)
names(Properties)[1:5] <- c(
  "Name", "IterANDDist", "Modifier", "EnvNum", "SpaceAND.RData"
)
Properties$FullName <- names(Diversity)
# Capture the position between the text (first group)
# and the set of numbers (somehow without the +).
# The \\K resets so that we do not capture any text.
patternString <- "((?>[a-zA-Z]+)(?=[0-9eE]))\\K"
# Split strings. Some of the trick will be to introduce
# a character to make the separation around. We use "_".
Properties <- Properties %>% dplyr::mutate(
  IterANDDist = gsub(pattern = patternString, 
                     replacement = "_", 
                     x = IterANDDist, perl = TRUE),
  Modifier = gsub(pattern = patternString, 
                  replacement = "_", 
                  x = Modifier, perl = TRUE),
  EnvNum = gsub(pattern = patternString, 
                replacement = "_", 
                x = EnvNum, perl = TRUE)
) %>% tidyr::separate(
  IterANDDist, into = c("Iter", "Distance"),
  sep = "[_]", fill = "right"
) %>% tidyr::separate(
  Modifier, into = c("Modifier", "ModIntensity"),
  sep = "[_]", fill = "right"
) %>% tidyr::separate(
  EnvNum, into = c("Env", "Environments"),
  sep = "[_]"
) %>% tidyr::separate(
  SpaceAND.RData, into = c("Space", ".RData"),
  sep = "[.]"
) %>% dplyr::select(
  -Name, -.RData, -Env
) %>% dplyr::mutate(
  Distance = dplyr::case_when(
    is.na(Distance) ~ "1e+00",
    TRUE ~ Distance
  )
)
Diversity <- lapply(1:length(Diversity),
                    function(i, df, nm) {
                      df[[i]] %>% mutate(
                        Simulation = nm[i]
                      )
                    }, 
                    df = Diversity,
                    nm = names(Diversity))
JaccardSpace <- lapply(1:length(JaccardSpace),
                    function(i, df, nm) {
                      df[[i]] %>% dplyr::bind_rows(
                        # Need to account for the by times...
                        # Generates attribute warnings.
                      ) %>% mutate(
                        Simulation = nm[i]
                      )
                    }, 
                    df = JaccardSpace,
                    nm = names(JaccardSpace))
JaccardTime <- lapply(1:length(JaccardTime),
                    function(i, df, nm) {
                      df[[i]] %>% dplyr::bind_rows(
                        # Need to account for the by envs...
                        # Generates attribute warnings.
                      ) %>% mutate(
                        Simulation = nm[i]
                      )
                    }, 
                    df = JaccardTime,
                    nm = names(JaccardTime))
SpeciesPresence <- lapply(1:length(SpeciesPresence),
                    function(i, df, nm) {
                      df[[i]] %>% mutate(
                        Simulation = nm[i]
                      )
                    }, 
                    df = SpeciesPresence,
                    nm = names(SpeciesPresence))
Diversity <- dplyr::left_join(
  dplyr::bind_rows(Diversity),
  Properties,
  by = c("Simulation" = "FullName")
)
JaccardSpace <- dplyr::left_join(
  dplyr::bind_rows(JaccardSpace),
  Properties,
  by = c("Simulation" = "FullName")
)
JaccardTime <- dplyr::left_join(
  dplyr::bind_rows(JaccardTime),
  Properties,
  by = c("Simulation" = "FullName")
)
SpeciesPresence <- dplyr::left_join(
  dplyr::bind_rows(SpeciesPresence),
  Properties,
  by = c("Simulation" = "FullName")
)
Diversity <- Diversity %>% dplyr::mutate(
  Distance = dplyr::case_when(
    is.na(Distance) ~ "1e+00",
    TRUE ~ Distance
  )
)

Alpha Richness

Overall

ggplot2::ggplot(
  Diversity %>% dplyr::filter(
    Measurement == "Richness",
    Environment != "Gamma",
    Space != "Ring",
    Environment != "Mean"
  ), 
  ggplot2::aes(
    x = Time,
    y = Value,
    color = factor(Environment),
    alpha = ifelse(Environment %in% c("3", "7", "Mean"), 1, 0.3)
  )
) + ggplot2::geom_line(
) + ggplot2::geom_line(
  data = Diversity %>% dplyr::filter(
    Measurement == "Richness",
    Environment != "Gamma",
    Space != "Ring",
    Environment == "Mean"
  ), 
  color = "black"
) + ggplot2::guides(
  alpha = "none"
) + ggplot2::scale_color_discrete(
  "Environment"
) + ggplot2::labs(
  y = "Richness",
  x = paste0("Time, ", divide_time_by, " units"),
  title = "Overview of Alpha Richness over Time by System Properties",
  caption = "Each row has the same arrival and extinction events."
) + ggplot2::facet_grid(
  Modifier + ModIntensity ~ Space + Distance
)

# ggplot2::ggsave(overallrich + ggplot2::coord_cartesian(ylim = c(0, 25)), filename = "MNA-AlphaRichness-Overview.pdf", dpi = "retina", width = 11, height = 8)
Plot_Richness <- function(df) {
  tempname <- paste(unique(df$Simulation), collapse = " ")
  
  temp <- ggplot2::ggplot(
    df %>% dplyr::filter(
      Measurement == "Richness",
      Environment != "Gamma",
      Environment != "Mean"
    ), 
    ggplot2::aes(
      x = Time,
      y = Value,
      color = factor(Environment),
      alpha = ifelse(Environment %in% c("3", "7", "Mean"), 1, 0.3)
    )
  ) + ggplot2::geom_line(
  ) + ggplot2::geom_line(
    data = df %>% dplyr::filter(
      Measurement == "Richness",
      Environment != "Gamma",
      Environment == "Mean"
    ), 
    color = "black"
  ) + ggplot2::guides(
    alpha = "none"
  ) + ggplot2::scale_color_discrete(
    "Environment"
  ) + ggplot2::labs(
    title = tempname,
    x = paste0("Time, ", divide_time_by, " units"),
    y = "Richness"
  )
  
  return(temp)
}
Plots_Richness_alpha <- Diversity %>% dplyr::group_split(
  Simulation
) %>% purrr::map(
  Plot_Richness
)
# In the next chunk, we use
# www.r-bloggers.com/2020/07/programmatically-create-new-geadings-and-outputs-in-rmarkdown/

Sim: 1

Sim: 2

Sim: 3

Sim: 4

Sim: 5

Sim: 6

Sim: 7

Sim: 8

Sim: 9

Sim: 10

Sim: 11

Sim: 12

Sim: 13

Sim: 14

Sim: 15

Sim: 16

Sim: 17

Sim: 18

Sim: 19

Sim: 20

Sim: 21

Sim: 22

Sim: 23

Sim: 24

Sim: 25

Sim: 26

Evenness

Overall

ggplot2::ggplot(
  Diversity %>% dplyr::filter(
    Measurement == "Evenness",
    Environment != "Gamma",
    Space != "Ring",
    Environment != "Mean"
  ), 
  ggplot2::aes(
    x = Time,
    y = Value,
    color = factor(Environment),
    alpha = ifelse(Environment %in% c("3", "7", "Mean"), 1, 0.3)
  )
) + ggplot2::geom_line(
) + ggplot2::geom_line(
  data = Diversity %>% dplyr::filter(
    Measurement == "Evenness",
    Environment != "Gamma",
    Space != "Ring",
    Environment == "Mean"
  ), 
  color = "black"
) + ggplot2::guides(
  alpha = "none"
) + ggplot2::scale_color_discrete(
  "Environment"
) + ggplot2::labs(
  y = "Evenness",
  x = paste0("Time, ", divide_time_by, " units"),
  title = "Overview of Evenness over Time by System Properties",
  caption = "Each row has the same arrival and extinction events."
) + ggplot2::facet_grid(
  Modifier + ModIntensity ~ Space + Distance
)

# ggplot2::ggsave(overallrich + ggplot2::coord_cartesian(ylim = c(0, 25)), filename = "MNA-AlphaRichness-Overview.pdf", dpi = "retina", width = 11, height = 8)
Plot_Evenness <- function(df) {
  tempname <- paste(unique(df$Simulation), collapse = " ")
  
  temp <- ggplot2::ggplot(
    df %>% dplyr::filter(
      Measurement == "Evenness",
      Environment != "Gamma",
      Environment != "Mean"
    ), 
    ggplot2::aes(
      x = Time,
      y = Value,
      color = factor(Environment),
      alpha = ifelse(Environment %in% c("3", "7", "Mean"), 1, 0.3)
    )
  ) + ggplot2::geom_line(
  ) + ggplot2::geom_line(
    data = df %>% dplyr::filter(
      Measurement == "Evenness",
      Environment != "Gamma",
      Environment == "Mean"
    ), 
    color = "black"
  ) + ggplot2::guides(
    alpha = "none"
  ) + ggplot2::scale_color_discrete(
    "Environment"
  ) + ggplot2::labs(
    title = tempname,
    x = paste0("Time, ", divide_time_by, " units"),
    y = "Evenness"
  )
  
  return(temp)
}
Plots_Evenness <- Diversity %>% dplyr::group_split(
  Simulation
) %>% purrr::map(
  Plot_Evenness
)
# In the next chunk, we use
# www.r-bloggers.com/2020/07/programmatically-create-new-headings-and-outputs-in-rmarkdown/

Sim: 1

Sim: 2

Sim: 3

Sim: 4

Sim: 5

Sim: 6

Sim: 7

Sim: 8

Sim: 9

Sim: 10

Sim: 11

Sim: 12

Sim: 13

Sim: 14

Sim: 15

Sim: 16

Sim: 17

Sim: 18

Sim: 19

Sim: 20

Sim: 21

Sim: 22

Sim: 23

Sim: 24

Sim: 25

Sim: 26

Gamma Richness

Richness

ggplot2::ggplot(
  Diversity %>% dplyr::filter(
    Measurement == "Richness",
    Environment == "Gamma",
    Space != "Ring"
  ), 
  ggplot2::aes(
    x = Time,
    y = Value
  )
) + ggplot2::geom_line(
) + ggplot2::labs(
  y = "Richness",
  x = paste0("Time, ", divide_time_by, " units"),
  title = "Gamma Richness over Time by System Properties",
  caption = "Each row has the same arrival and extinction events."
) + ggplot2::facet_grid(
  Modifier + ModIntensity ~ Space + Distance
) + ggplot2::coord_cartesian(ylim = c(0, 45))

# ggplot2::ggsave(overallgamma, filename = "MNA-GammaRichness-Overview.pdf", dpi = "retina", width = 11, height = 8)

Beta Richness

\(\gamma - \alpha\)

ggplot2::ggplot(
  Diversity %>% dplyr::filter(
    Measurement == "BetaSpeciesMissing",
    Environment != "Gamma",
    Space != "Ring",
    Environment != "Mean"
  ), 
  ggplot2::aes(
    x = Time,
    y = Value,
    color = factor(Environment),
    alpha = ifelse(Environment %in% c("3", "7", "Mean"), 1, 0.3)
  )
) + ggplot2::geom_line(
) + ggplot2::geom_line(
    data = Diversity %>% dplyr::filter(
        Measurement == "BetaSpeciesMissing",
        Environment != "Gamma",
        Space != "Ring",
        Environment != "Mean"
    ) %>% dplyr::group_by(
        Modifier, ModIntensity, Space, Distance, Time
    ) %>% dplyr::summarise(
        Environment = "Mean",
        Value = mean(Value, na.rm = TRUE)
    ), color = "black"
) + ggplot2::guides(
  alpha = "none"
) + ggplot2::scale_color_discrete(
  "Environment"
) + ggplot2::labs(
  y = "Absolute Species Turnover", # en.wikipedia.org/wiki/Beta_diversity
  x = paste0("Time, ", divide_time_by, " units"),
  title = "Overview of Gamma - Alpha Richness over Time by System Properties",
  caption = "Each row has the same arrival and extinction events."
) + ggplot2::facet_grid(
  Modifier + ModIntensity ~ Space + Distance
)

# ggplot2::ggsave(overallbetamiss, filename = "MNA-BetaMissing-Overview.pdf", dpi = "retina", width = 11, height = 8)

\(\alpha / \gamma\)

ggplot2::ggplot(
    Diversity %>% dplyr::filter(
        Measurement == "BetaSpeciesPercentage",
        Environment != "Gamma",
        Space != "Ring",
        Environment != "Mean"
    ), 
    ggplot2::aes(
        x = Time,
        y = Value,
        color = factor(Environment),
        alpha = ifelse(Environment %in% c("3", "7", "Mean"), 1, 0.3)
    )
) + ggplot2::geom_line(
) + ggplot2::geom_line(
    data = Diversity %>% dplyr::filter(
        Measurement == "BetaSpeciesPercentage",
        Environment != "Gamma",
        Space != "Ring",
        Environment != "Mean"
    ) %>% dplyr::group_by(
        Modifier, ModIntensity, Space, Distance, Time
    ) %>% dplyr::summarise(
        Environment = "Mean",
        Value = mean(Value, na.rm = TRUE)
    ), color = "black"
) + ggplot2::guides(
    alpha = "none"
) + ggplot2::scale_color_discrete(
    "Environment"
) + ggplot2::labs(
    y = "Percentage Species Present", # en.wikipedia.org/wiki/Beta_diversity
    x = paste0("Time, ", divide_time_by, " units"),
    title = "Overview of Alpha/Gamma Richness over Time by System Properties",
    caption = "Each row has the same arrival and extinction events."
) + ggplot2::facet_grid(
    Modifier + ModIntensity ~ Space + Distance
)

# ggplot2::ggsave(overallbetapercent, filename = "MNA-BetaPercent-Overview.pdf", dpi = "retina", width = 11, height = 8)

Alpha vs Gamma

Diversity_AG <- dplyr::left_join(
  Diversity %>% dplyr::filter(
    Measurement == "Richness",
    Space != "Ring",
    Environment != "Gamma"
  ), 
  Diversity %>% dplyr::filter(
    Measurement == "Richness",
    Space != "Ring",
    Environment == "Gamma"
  ) %>% dplyr::rename(
    Gamma = Value
  ) %>% dplyr::select(
    -Environment
  )
) %>% dplyr::mutate(
  Distance = ifelse(is.na(Distance), 1, Distance)
)
Joining, by = c("Time", "Measurement", "Simulation", "Iter", "Distance", "Modifier", "ModIntensity", "Environments", "Space")
Diversity_AG_Binned <- Diversity_AG %>% dplyr::mutate(
    TimeFloor = floor(Time * 10) / 10
) %>% dplyr::distinct(
    Modifier, ModIntensity, Space, Distance, # Simulation/Facets
    Environment, TimeFloor, # Grouping Bins
    Value, Gamma # Values. If either moves, the trajectory entered a new square.
)
# ggplot2::ggplot(
#   temp %>% dplyr::filter(
#     Modifier == "Result",
#     Space == "None",
#     Environment != "Mean"
#   ), ggplot2::aes(
#     x = Gamma,
#     y = Value
#   )
# ) + ggplot2::geom_bin2d(
# ) + ggplot2::scale_fill_viridis_c(
# ) + ggplot2::labs(
#   Title = "No Spatial Structure, Equal Extinction & Arrival Rates",
#   x = "Gamma Richness",
#   y = "Alpha Richness"
# )
ggplot2::ggplot(
    Diversity_AG %>% dplyr::filter(
        Environment != "Mean",
        Space != "Ring"
    ), ggplot2::aes(
        x = Value,
        y = Gamma
    )
) + ggplot2::geom_bin2d(
) + ggplot2::scale_fill_viridis_c(
    trans = "log10"
) + ggplot2::geom_point(
    data = Diversity_AG %>% dplyr::filter(
        Environment != "Mean",
        Space != "Ring"
    ) %>% dplyr::group_by(
        Modifier, ModIntensity, Space, Distance
    ) %>% dplyr::summarise(
        Gamma = mean(Gamma, na.rm = TRUE),
        Value = mean(Value, na.rm = TRUE)
    ), color = "red", size = 2, shape = 4
) + ggplot2::labs(
    x = "Alpha Richness",
    y = "Gamma Richness"
) + ggplot2::facet_grid(
    Modifier + ModIntensity ~ Space + Distance
) + ggplot2::geom_abline(slope = 1, intercept = 0)

# ggplot2::ggsave(overallalphagamma, filename = "MNA-AlphaGamma-Overview.pdf", dpi = "retina", width = 11, height = 8)
ggplot2::ggplot(
    Diversity_AG_Binned %>% dplyr::filter(
        Environment != "Mean",
        Space != "Ring"
    ), ggplot2::aes(
        x = Value,
        y = Gamma
    )
) + ggplot2::geom_bin2d(
) + ggplot2::scale_fill_viridis_c(
    trans = "log10"
) + ggplot2::geom_point(
    data = Diversity_AG_Binned %>% dplyr::filter(
        Environment != "Mean",
        Space != "Ring"
    ) %>% dplyr::group_by(
        Modifier, ModIntensity, Space, Distance
    ) %>% dplyr::summarise(
        Gamma = mean(Gamma, na.rm = TRUE),
        Value = mean(Value, na.rm = TRUE)
    ), color = "red", size = 2, shape = 4
) + ggplot2::labs(
    x = "Alpha Richness",
    y = "Gamma Richness",
    subtitle = "Trajectories binned by time to equalise time steps."
) + ggplot2::facet_grid(
    Modifier + ModIntensity ~ Space + Distance
) + ggplot2::geom_abline(slope = 1, intercept = 0)

# ggplot2::ggsave(overallalphagammabin, filename = "MNA-AlphaGammaBinned-Overview.pdf", dpi = "retina", width = 11, height = 8)
ggplot2::ggplot( 
    Diversity_AG_Binned %>% dplyr::filter(
        Environment != "Mean",
        Space != "Ring"
    ) %>% dplyr::group_by(
        Modifier, ModIntensity, Space, Distance
    ) %>% dplyr::summarise(
        Gamma = mean(Gamma, na.rm = TRUE),
        Value = mean(Value, na.rm = TRUE)
    ), 
    ggplot2::aes(
        x = Value,
        y = Gamma,
        color = interaction(Modifier, ModIntensity),
        shape = interaction(Space, Distance)
    )
) + ggplot2::geom_point(
    size = 2
) + ggplot2::labs(
    x = "Alpha Richness",
    y = "Gamma Richness",
    subtitle = "Trajectories binned by time to equalise time steps."
) + ggplot2::geom_abline(slope = 1, intercept = 0)

# ggplot2::ggsave(overallalphagammamean, filename = "MNA-AlphaGammaBinned-Means.pdf", dpi = "retina", width = 11, height = 8)

Jaccard, Space

ggplot2::ggplot(
  JaccardSpace %>% dplyr::filter(Time > 3, Space != "Ring"),
  ggplot2::aes(x = Time, y = Jaccard, 
               color = interaction(Env1, Env2)
  )
) + ggplot2::geom_line(
  alpha = 0.3
) + ggplot2::geom_line(
  data = JaccardSpace %>% dplyr::filter(Time > 3, Space != "Ring") %>% dplyr::group_by(
    Time, Distance, Modifier, ModIntensity, Space
  ) %>% dplyr::summarise(
    Jaccard = mean(Jaccard, na.rm = TRUE)
  ),
  ggplot2::aes(
    x = Time, y = Jaccard
  ),
  inherit.aes = FALSE, color = "black"
) + ggplot2::facet_grid(
    Modifier + ModIntensity ~ Space + Distance
) + ggplot2::guides(
  color = "none"
)

Jaccard, Time

ggplot2::ggplot(
  JaccardTime %>% dplyr::filter(
    Space != "Ring"
  ) %>% dplyr::group_by(
    Environment, Distance, Space, Modifier, ModIntensity
  ) %>% dplyr::mutate(
    TimeDifference = Time2 - Time1
  ),
  ggplot2::aes(
    x = TimeDifference,
    y = Jaccard
  )
) + ggplot2::geom_bin2d(
) + ggplot2::facet_grid(
    Modifier + ModIntensity ~ Space + Distance
) + ggplot2::scale_fill_viridis_c(
  trans = "log"
)

ggplot2::ggplot(
  JaccardTime %>% dplyr::filter(
    Space != "Ring",
    Space == "None",
    Modifier == "Result"
  ) %>% dplyr::group_by(
    Environment, Distance, Space, Modifier, ModIntensity
  ) %>% dplyr::mutate(
    TimeDifference = Time2 - Time1
  ),
  ggplot2::aes(
    x = TimeDifference,
    y = Jaccard
  )
) + ggplot2::geom_bin2d(
) + ggplot2::facet_wrap(
    ~ Environment
) + ggplot2::scale_fill_viridis_c(
  trans = "log"
)

Species Presence

# ggplot2::ggplot(
#   SpeciesPresence %>% dplyr::filter(
#     Space != "Ring",
#     TimeFloor > 0.2 # Remove "burn-in" which has "impossibly" high presence. 
#   ),
#   ggplot2::aes(
#     x = TimeFloor,
#     y = Species
#   )
# ) + ggplot2::geom_bin2d(
#   binwidth = c(0.1, 1)
# ) + ggplot2::scale_fill_viridis_c(
# )+ ggplot2::facet_grid(
#   Modifier + ModIntensity ~ Space + Distance
# )
ggplot2::ggplot(
  SpeciesPresence %>% dplyr::filter(
    Space != "Ring"
  ) %>% dplyr::group_by(
    Modifier, ModIntensity, Space, Distance,
    Species, Time
  ) %>% dplyr::summarise(
    Count = n()
  ),
  ggplot2::aes(x = Time, y = Species, color = Count)
) + ggplot2::geom_point(
  shape = '.'
) + ggplot2::scale_color_viridis_c(
) + ggplot2::facet_grid(
  Modifier + ModIntensity ~ Space + Distance
) + ggplot2::geom_hline(
  yintercept = 34.5, color = "red"
)

ggplot2::ggplot(
  SpeciesPresence %>% dplyr::filter(
    Space != "Ring"
  ) %>% dplyr::group_by(
    Modifier, ModIntensity, Space, Distance,
    Species, Time
  ) %>% dplyr::summarise(
    Count = n()
  ),
  ggplot2::aes(x = Time, y = Species, color = Count)
) + ggplot2::geom_point(
  shape = '.'
) + ggplot2::scale_color_viridis_c(
  direction = -1
) + ggplot2::facet_grid(
  Modifier + ModIntensity ~ Space + Distance
) + ggplot2::geom_hline(
  yintercept = 34.5, color = "red"
)

# Brute forcing here because I would rather position myself to move on if possible.
# This works because all of the pools are the same (except that the original does not use factors because stringsAsFactors differed between the machines generating the systems).
# > all.equal(PoolsMats$`MNA-Ext10-PoolMats-Env10.RData`, PoolsMats$`MNA-Ext0.1-PoolMats-Env10.RData`)
# [1] TRUE
# > all.equal(PoolsMats$`MNA-Ext10-PoolMats-Env10.RData`, PoolsMats$`MNA-Arr0.1-PoolMats-Env10.RData`)
# [1] TRUE
# > all.equal(PoolsMats$`MNA-Ext10-PoolMats-Env10.RData`, PoolsMats$`MNA-Arr10-PoolMats-Env10.RData`)
# [1] TRUE
SpeciesPresence$Sizes <- PoolsMats$`MNA-FirstAttempt-PoolMats-Env10.RData`$Pool$Size[SpeciesPresence$Species]
ggplot2::ggplot(
  SpeciesPresence %>% dplyr::filter(
    Space != "Ring"
  ) %>% dplyr::group_by(
    Modifier, ModIntensity, Space, Distance,
    Species, Time, Sizes
  ) %>% dplyr::summarise(
    Count = n()
  ) %>% dplyr::arrange(
    Sizes
  ) %>% dplyr::ungroup(
  ) %>% dplyr::mutate(
    Species = factor(Species, levels = Species)
  ),
  ggplot2::aes(x = Time, y = Species, color = Count)
) + ggplot2::geom_point(
  shape = '.'
) + ggplot2::scale_color_viridis_c(
) + ggplot2::facet_grid(
  Modifier + ModIntensity ~ Space + Distance
) + ggplot2::geom_hline(
  yintercept = 34.5, color = "red"
)
Error in `levels<-`(`*tmp*`, value = as.character(levels)) : 
  factor level [2] is duplicated

Species Abundance

# ggplot2::ggplot(
#   SpeciesPresence %>% dplyr::filter(
#     Space != "Ring",
#     TimeFloor > 0.2 # Remove "burn-in" which has "impossibly" high presence. 
#   ),
#   ggplot2::aes(
#     x = TimeFloor,
#     y = Abundance
#   )
# ) + ggplot2::geom_bin2d(
# ) + ggplot2::scale_fill_viridis_c(
# ) + ggplot2::facet_grid(
#   Modifier + ModIntensity ~ Space + Distance
# ) + ggplot2::scale_y_log10(
# ) 
ggplot2::ggplot(
  SpeciesPresence %>% dplyr::filter(
    Space != "Ring"
  ) %>% dplyr::mutate(
    Abundance = round(Abundance)
  ) %>% dplyr::group_by(
    Modifier, ModIntensity, Space, Distance,
    Abundance, Time
  ) %>% dplyr::summarise(
    Count = n()
  ),
  ggplot2::aes(x = Time, y = Abundance, color = Count)
) + ggplot2::geom_point(
  shape = '.'
) + ggplot2::scale_color_viridis_c(
  trans = "log"
) + ggplot2::facet_grid(
  Modifier + ModIntensity ~ Space + Distance
) + ggplot2::scale_y_log10(
)

Species Sizes

(Recall that there is a threshold above which we have consumers and below which we have producers. This will be denoted with a bright line at the threshold.)

# ggplot2::ggplot(
#   SpeciesPresence %>% dplyr::filter(
#     Space != "Ring",
#     TimeFloor > 0.2 # Remove "burn-in" which has "impossibly" high presence. 
#   ),
#   ggplot2::aes(
#     x = TimeFloor,
#     y = Sizes
#   )
# ) + ggplot2::geom_bin2d(
#   binwidth = c(0.1, 0.03)
# ) + ggplot2::scale_fill_viridis_c(
# ) + ggplot2::facet_grid(
#   Modifier + ModIntensity ~ Space + Distance
# ) + ggplot2::scale_y_log10(
# ) + ggplot2::geom_hline(
#   yintercept = 0.1, color = "red"
# )

ggplot2::ggplot(
  SpeciesPresence %>% dplyr::filter(
    Space != "Ring"
  ) %>% dplyr::group_by(
    Modifier, ModIntensity, Space, Distance,
    Sizes, Time
  ) %>% dplyr::summarise(
    Count = n()
  ),
  ggplot2::aes(x = Time, y = Sizes, color = Count)
) + ggplot2::geom_point(
  shape = '.'
) + ggplot2::scale_color_viridis_c(
) + ggplot2::facet_grid(
  Modifier + ModIntensity ~ Space + Distance
) + ggplot2::geom_hline(
  yintercept = 0.1, color = "red"
) + ggplot2::scale_y_log10(
)

Compare with the distribution of traits amongst species.

ggplot2::ggplot(
  PoolsMats$`MNA-FirstAttempt-PoolMats-Env10.RData`$Pool,
  ggplot2::aes(
    x = Size,
    fill = Type
  )
) + ggplot2::geom_histogram(#ggplot2::geom_density(
  #alpha = 0.5, adjust = 1/10
  bins = 100
) + ggplot2::scale_x_log10() + ggplot2::coord_flip()

Events

Preparation

Calculate_Events <- function(result, abundanceTime = divide_time_by, thinning = by_for_thinning) {
  abund <- result$Abundance
  abund[, -1] <- abund[, -1] > 0 # Presence-Absence
  abundDiff <- apply(abund[, -1], 2, diff) 
  # Arrival (1) Elimination (-1)
  # if arrival at time 93,
  # 92nd entry is 1.
  abundDiff <- cbind(
    abund[-1, 1] * abundanceTime, abundDiff
  )
  
  Events <- lapply(
    1:ncol(abundDiff[, -1]),
    function(i, ab, tm, sp) {
      arrivals <- which(ab[, i] == 1)
      extincts <- which(ab[, i] == -1)
      
      if (length(arrivals) + length(extincts) == 0) {
        return(NULL)
      } 
      
      data.frame(
        Times = c(tm[arrivals], tm[extincts]),
        Species = ((i - 1) %% sp) + 1, # 1:1000 -> 1:100
        Environment = ((i - 1) %/% sp) + 1,
        Type = c(rep("Arrival", length(arrivals)),
                  rep("Extinct", length(extincts))),
        stringsAsFactors = FALSE
      )
    },
    ab = abundDiff[, -1],
    tm = abundDiff[, 1],
    sp = ncol(abundDiff[, -1]) / result$NumEnvironments#,
    #ne = result$NumEnvironments
  ) %>% dplyr::bind_rows(
  ) %>% dplyr::arrange(
    Times, Species, Environment, Type
  )
  
  # Now we check to see which events are in the record.
  # Note that, due to thinning, we do have a theoretical
  # problem: an event time might be misrecorded when
  # extracted from the abundance record.
  # Hence we cannot just use filtering join operations.
  # Since we know the maximum time step size and the
  # thinning, we know that we should detect a change
  # within (thinning) * (max. time step size) units.
  maximumGap <- thinning * result$Parameters$MaximumTimeStep
  
  result$Events$Type <- as.character(result$Events$Type)
  
  # Connect all same event, even with different times.
  # Remove those that cannot be the same event.
  # Treat this as the list of Neutral Events that
  # actually happened.
  EventsOfficial <- result$Events %>% dplyr::left_join(
    Events, 
    by = c("Species", "Environment", "Type")
  ) %>% dplyr::mutate(
    # dplyr::filter( # Filtering does not work.
    # We are seeing losses of about 50% with filter.
    # "Rows in x with no match in y will have NA values in the new columns." 
    # -> Times.y will be NA.
    # Times.y is the detected time.
    # Times.x is the recorded action's time.
    # Note that we can get false readings from subtracting two almost the same 
    # numbers, so we need to appeal to machine precision. 
    # See all.equal's tolerance argument.
    `Times.y` = dplyr::case_when(
      is.na(`Times.y`) ~ as.double(NA),
      (
      `Times.y` - `Times.x` < maximumGap + sqrt(.Machine$double.eps) & 
        `Times.y` - `Times.x` >= -sqrt(.Machine$double.eps)) ~ `Times.y`,
      TRUE ~ as.double(NA)
    )
  ) %>% dplyr::group_by(
    `Times.x`, Species, Environment, Type, Success
    # Don't discard Success, others are true groups.
    # We want to preserve the first `Times.y`
    # (in case an event happens multiple times)
    # but if there are no numerics,
    # we instead want to keep one of the NAs.
  ) %>% dplyr::summarise(
    `Times.y` = if (length(na.omit(`Times.y`)) == 0) NA else min(`Times.y`, na.rm = TRUE)
  ) %>% dplyr::ungroup(
  ) %>% dplyr::rename(
    TimeImplemented = `Times.x`,
    TimeDetected = `Times.y`
  )
  
  # Events that were not detected but were successful.
  # If this is the case, something happened and was 
  # undone in the same timespan.
  # This might happen due to arrivals from adjacent 
  # patches.
  # I.e. elimination coinciding with arrival or 
  # arrival being too dissipated by dispersal.
  # This probably shouldn't happen in the disconnected system.
  EventsNotDetected <- EventsOfficial %>% dplyr::filter(
    is.na(TimeDetected), Success == TRUE
  # ) %>% dplyr::select(
  #   -`Times.y`
  # ) %>% dplyr::rename(
  #   Times = `Times.x`
  ) %>% dplyr::mutate(
    Neutral = TRUE,
    Detected = FALSE
  )
  
  # Events that were detected and were successful. 'True Positives'
  # We recorded them as having happened in Events and Abundance.
  # These are also Neutral with high probability.
  EventsDetected <- EventsOfficial %>% dplyr::filter(
    !is.na(TimeDetected), Success == TRUE
    # ) %>% dplyr::select(
    # # We keep Times.y for comparison with Events.
    #   -`Times.x`
    # ) %>% dplyr::rename(
    #   Times = `Times.y`
    ) %>% dplyr::mutate(
      Neutral = TRUE,
      Detected = TRUE
    )
  
  # Events that were not detected and were not successful. 'True Negatives'
  # Also Events that were detected and were not successful. 'False Positives'?
  # The detection must be of a different event if the event
  # we recorded was unsuccessful after all.
  EventsFailed <- EventsOfficial %>% dplyr::filter(
    #is.na(`Times.y`), 
    Success != TRUE
    # ) %>% dplyr::select(
    #   -`Times.y`
    # ) %>% dplyr::rename(
    #   Times = `Times.x`
    ) %>% dplyr::mutate(
      Neutral = TRUE,
      Detected = FALSE
    )
  
  # So we have events that were detected but not successful.
  # Such events should probably be listed twice: 
  #   once as neutral (the failure, above)
  #   once as non-neutral (the detected event, below).
  # (Note Events are from abundance and thus detected.)
  EventsNotOfficial <- Events %>% dplyr::rename(
    TimeDetected = Times
  ) %>% dplyr::anti_join(
    EventsDetected, by = c("TimeDetected", "Species", "Environment", "Type")
  )  %>% dplyr::mutate(
    Success = TRUE,
    Neutral = FALSE,
    Detected = TRUE
  ) 
  
  # The remainder of event space is events that are
  # not neutral and not successful or 
  # events that were not implemented.
  
  # Note then that, if everything went well
  stopifnot(nrow(EventsNotOfficial) + nrow(EventsDetected) == nrow(Events),
            nrow(EventsDetected) + nrow(EventsFailed) + nrow(EventsNotDetected) == nrow(result$Events))

  return(dplyr::bind_rows(
    EventsDetected,
    EventsNotDetected,
    EventsFailed,
    EventsNotOfficial
  ) %>% dplyr::mutate(
    Times = dplyr::case_when(
      !is.na(TimeImplemented) ~ TimeImplemented,
      !is.na(TimeDetected) ~ TimeDetected
    )
  ) %>% dplyr::arrange(Times, Environment, Species, Type))
}
Events <-  sapply(
  USE.NAMES = TRUE, simplify = FALSE,
  Results, function(result) {
    if (length(result) == 1 && is.na(result)) {
      # Problem case.
      return(NA)
    }
    # print(paste("Calculating", Sys.time()))
    
    # Calculate the diversity.
    # We will need to extract the system properties from
    # the file names which we carry through using sapply.
    return(Calculate_Events(result))
  }
)
Events <- lapply(1:length(Events),
                    function(i, df, nm) {
                      df[[i]] %>% mutate(
                        Simulation = nm[i]
                      )
                    }, 
                    df = Events,
                    nm = names(Events))
EventsSuccesses <- lapply(Events, function(Event) {
  Event %>% dplyr::filter(
    Success == TRUE
  ) %>% dplyr::group_by(
    Environment
  ) %>% dplyr::arrange(
    Times
  ) %>% dplyr::mutate(
    InterarrivalTime = Times - lag(Times), 
    Dynamic = !Neutral, 
    Sequence = cumsum(Neutral)
  ) %>% dplyr::group_by(
    Environment, Sequence
  ) %>% dplyr::mutate(
    EventInSequence = cumsum(Dynamic)
  )
}) 
Events <- lapply(Events, function(Event) {
  Event %>% dplyr::group_by(
    Environment
  ) %>% dplyr::arrange(
    Times
  ) %>% dplyr::mutate(
    InterarrivalTime = Times - lag(Times), 
    Dynamic = !Neutral, 
    Sequence = cumsum(Neutral)
  ) %>% dplyr::group_by(
    Environment, Sequence
  ) %>% dplyr::mutate(
    EventInSequence = cumsum(Dynamic)
  )
}) 
Events <- dplyr::left_join(
  dplyr::bind_rows(Events),
  Properties,
  by = c("Simulation" = "FullName")
)
EventsSuccesses <- dplyr::left_join(
  dplyr::bind_rows(EventsSuccesses),
  Properties,
  by = c("Simulation" = "FullName")
)
Events <- Events %>% dplyr::mutate(
  Distance = dplyr::case_when(
    is.na(Distance) ~ "1e+00",
    TRUE ~ Distance
  )
)
EventsSuccesses <- EventsSuccesses %>% dplyr::mutate(
  Distance = dplyr::case_when(
    is.na(Distance) ~ "1e+00",
    TRUE ~ Distance
  )
)
# Retrieve the Characteristic Rate used.
# Since all of the Pools and Matrices are the same, they all have the same characteristic rate.
# There is a fudge here. Looking back at the code, the first matrix was used, rather than looking over all of the matrices, but we note that the results are essentially the same.
# Perhaps something to be more careful of for the next round of simulations...
CharacteristicRate <- max(abs(eigen(PoolsMats[[1]]$InteractionMatrices$Mats[[1]])$values))
set.seed(1)
exampleData <- Events[[2]] %>% dplyr::filter(Neutral) %>% dplyr::arrange(Times) %>% pull(Times) %>% diff
fitdistrplus::descdist(exampleData, boot = 100)
censData <- ifelse(exampleData == 0, .Machine$double.eps, exampleData)
exampleFitsNotHeavy <- list(
  exp = fitdistrplus::fitdist(censData, "exp", method = "mle"),
  gamma = fitdistrplus::fitdist(censData, 
                              "gamma", method = "mle"),
  weibull = fitdistrplus::fitdist(censData, 
                              "weibull", method = "mle")
)
exampleFitsHeavy <- lapply(
    c(poweRlaw::conexp, poweRlaw::conlnorm, poweRlaw::conpl, poweRlaw::conweibull), function(f) {f$new(censData)}
)

exampleFitsHeavy <- lapply(
  exampleFitsHeavy, 
  function(d) {
    d$setXmin(poweRlaw::estimate_xmin(d, xmax = Inf))
    d
    } 
)
  
names(exampleFitsHeavy) <- c("exp", "lnorm", "pl", "weibull")
fitdistrplus::gofstat(exampleFitsNotHeavy)
quiet(exampleData_gamlss <- gamlss::fitDist(exampleData))
exampleData_gamlss
quiet(censData_gamlss <- gamlss::fitDist(censData))
exampleData_gamlss
exampleFitsHeavy

Plots

Full x Range

All Events, By Number in Sequence, Time by Environment
ggplot2::ggplot(
    Events %>% dplyr::filter(
        Space != "Ring"
    ),
    ggplot2::aes(
        x = InterarrivalTime,
        fill = factor(EventInSequence)
    )
) + ggplot2::geom_density(
  alpha = 0.25
) + ggplot2::scale_fill_viridis_d(
  "Event #"
) + ggplot2::facet_grid(
    Modifier + ModIntensity ~ Space + Distance
) + ggplot2::scale_x_log10() #-> environmenteventssequence
# ggplot2::ggsave(environmenteventssequence, filename = "MNA-EventEnvironmentArrivalTimes-Sequence.pdf", dpi = "retina", width = 11, height = 8)
All Events, By Neutral/Dynamic, Time by Environment
ggplot2::ggplot(
    Events %>% dplyr::filter(
        Space != "Ring"
    ),
    ggplot2::aes(
        x = InterarrivalTime,
        fill = Neutral
    )
) + ggplot2::geom_density(
  alpha = 0.25
) + ggplot2::scale_fill_viridis_d(
) + ggplot2::facet_grid(
    Modifier + ModIntensity ~ Space + Distance
) + ggplot2::scale_x_log10() #-> environmenteventsneutral
# ggplot2::ggsave(environmenteventsneutral, filename = "MNA-EventEnvironmentArrivalTimes-Overview.pdf", dpi = "retina", width = 11, height = 8)
All Events, By Number in Sequence, Overall Time
Events %>% dplyr::group_by(
    Simulation, Iter, Distance, 
    Modifier, ModIntensity, Environments, Space
) %>% dplyr::arrange(
    Times
) %>% dplyr::mutate(
    InterarrivalTime = Times - lag(Times), 
    Dynamic = !Neutral, 
    Sequence = cumsum(Neutral)
) %>% dplyr::group_by(
    Environment, Sequence
) %>% dplyr::mutate(
    EventInSequence = cumsum(Dynamic)
) %>% dplyr::filter(
    Space != "Ring"
) %>% ggplot2::ggplot(ggplot2::aes(
    x = InterarrivalTime,
    fill = factor(EventInSequence)
)
) + ggplot2::geom_density(
    alpha = 0.25
) + ggplot2::scale_fill_viridis_d(
  "Event #"
) + ggplot2::facet_grid(
    Modifier + ModIntensity ~ Space + Distance
) + ggplot2::scale_x_log10() + ggplot2::coord_cartesian(ylim = c(0, 2)) # -> overalleventssequence
# ggplot2::ggsave(overalleventssequence, filename = "MNA-EventOverallArrivalTimes-Sequence.pdf", dpi = "retina", width = 11, height = 8)
All Events, By Neutral/Dynamics, Overall Time
Events %>% dplyr::group_by(
    Simulation, Iter, Distance, 
    Modifier, ModIntensity, Environments, Space
) %>% dplyr::arrange(
    Times
) %>% dplyr::mutate(
    InterarrivalTime = Times - lag(Times), 
    Dynamic = !Neutral, 
    Sequence = cumsum(Neutral)
) %>% dplyr::group_by(
    Environment, Sequence
) %>% dplyr::mutate(
    EventInSequence = cumsum(Dynamic)
) %>% dplyr::filter(
    Space != "Ring"
) %>% ggplot2::ggplot(ggplot2::aes(
    x = InterarrivalTime,
    fill = Neutral
)
) + ggplot2::geom_density(
    alpha = 0.25
) + ggplot2::scale_fill_viridis_d(
) + ggplot2::facet_grid(
    Modifier + ModIntensity ~ Space + Distance
) + ggplot2::scale_x_log10() # -> overalleventsneutral
# ggplot2::ggsave(overalleventsneutral, filename = "MNA-EventOverallArrivalTimes-Overview.pdf", dpi = "retina", width = 11, height = 8)
Successful Events, By Number in Sequence, Time by Environment
ggplot2::ggplot(
    EventsSuccesses %>% dplyr::filter(
        Space != "Ring"
    ),
    ggplot2::aes(
        x = InterarrivalTime,
        fill = factor(EventInSequence)
    )
) + ggplot2::geom_density(
  alpha = 0.25
) + ggplot2::scale_fill_viridis_d(
  "Event #"
) + ggplot2::facet_grid(
    Modifier + ModIntensity ~ Space + Distance
) + ggplot2::scale_x_log10(
) + ggplot2::coord_cartesian(
  ylim = c(0, 2)
) #-> environmenteventssuccesssequence
# ggplot2::ggsave(environmenteventssuccesssequence, filename = "MNA-EventSuccessEnvironmentArrivalTimes-Sequence.pdf", dpi = "retina", width = 11, height = 8)
Successful Events, By Neutral/Dynamics, Time by Environment
ggplot2::ggplot(
    EventsSuccesses %>% dplyr::filter(
        Space != "Ring"
    ),
    ggplot2::aes(
        x = InterarrivalTime,
        fill = Neutral
    )
) + ggplot2::geom_density(
  alpha = 0.25
) + ggplot2::scale_fill_viridis_d(
) + ggplot2::facet_grid(
    Modifier + ModIntensity ~ Space + Distance
) + ggplot2::scale_x_log10() #-> environmenteventssuccessneutral
# ggplot2::ggsave(environmenteventssuccessneutral, filename = "MNA-EventSuccessEnvironmentArrivalTimes-Overview.pdf", dpi = "retina", width = 11, height = 8)
Successful Events, By Number in Sequence, Overall Time
EventsSuccesses %>% dplyr::group_by(
    Simulation, Iter, Distance, 
    Modifier, ModIntensity, Environments, Space
) %>% dplyr::arrange(
    Times
) %>% dplyr::mutate(
    InterarrivalTime = Times - lag(Times), 
    Dynamic = !Neutral, 
    Sequence = cumsum(Neutral)
) %>% dplyr::group_by(
    Environment, Sequence
) %>% dplyr::mutate(
    EventInSequence = cumsum(Dynamic)
) %>% dplyr::filter(
    Space != "Ring"
) %>% ggplot2::ggplot(ggplot2::aes(
    x = InterarrivalTime,
    fill = factor(EventInSequence)
)
) + ggplot2::geom_density(
    alpha = 0.25
) + ggplot2::scale_fill_viridis_d(
  "Event #"
) + ggplot2::facet_grid(
    Modifier + ModIntensity ~ Space + Distance
) + ggplot2::scale_x_log10() + ggplot2::coord_cartesian(ylim = c(0, 2)) # -> overalleventssuccesssequence
# ggplot2::ggsave(overalleventssuccesssequence, filename = "MNA-EventSuccessOverallArrivalTimes-Sequence.pdf", dpi = "retina", width = 11, height = 8)
Successful Events, By Neutral/Dynamics, Overall Time
EventsSuccesses %>% dplyr::group_by(
    Simulation, Iter, Distance, 
    Modifier, ModIntensity, Environments, Space
) %>% dplyr::arrange(
    Times
) %>% dplyr::mutate(
    InterarrivalTime = Times - lag(Times), 
    Dynamic = !Neutral, 
    Sequence = cumsum(Neutral)
) %>% dplyr::group_by(
    Environment, Sequence
) %>% dplyr::mutate(
    EventInSequence = cumsum(Dynamic)
) %>% dplyr::filter(
    Space != "Ring"
) %>% ggplot2::ggplot(ggplot2::aes(
    x = InterarrivalTime,
    fill = Neutral
)
) + ggplot2::geom_density(
    alpha = 0.25
) + ggplot2::scale_fill_viridis_d(
) + ggplot2::facet_grid(
    Modifier + ModIntensity ~ Space + Distance
) + ggplot2::scale_x_log10() # -> overalleventssuccessneutral
# ggplot2::ggsave(overalleventssuccessneutral, filename = "MNA-EventSuccessOverallArrivalTimes-Overview.pdf", dpi = "retina", width = 11, height = 8)

Trunc. x Range

All Events, By Number in Sequence, Time by Environment
ggplot2::ggplot(
    Events %>% dplyr::filter(
        Space != "Ring"
    ),
    ggplot2::aes(
        x = InterarrivalTime,
        fill = factor(EventInSequence)
    )
) + ggplot2::geom_density(
  alpha = 0.25
) + ggplot2::scale_fill_viridis_d(
  "Event #"
) + ggplot2::facet_grid(
    Modifier + ModIntensity ~ Space + Distance
) + ggplot2::scale_x_log10(
) + ggplot2::coord_cartesian(
  xlim = c(1e-1, 1e4)
) #-> environmenteventssequence
# ggplot2::ggsave(environmenteventssequence, filename = "MNA-EventEnvironmentArrivalTimes-Sequence.pdf", dpi = "retina", width = 11, height = 8)
All Events, By Neutral/Dynamic, Time by Environment
ggplot2::ggplot(
    Events %>% dplyr::filter(
        Space != "Ring"
    ),
    ggplot2::aes(
        x = InterarrivalTime,
        fill = Neutral
    )
) + ggplot2::geom_density(
  alpha = 0.25
) + ggplot2::scale_fill_viridis_d(
) + ggplot2::facet_grid(
    Modifier + ModIntensity ~ Space + Distance
) + ggplot2::scale_x_log10(
) + ggplot2::coord_cartesian(
  xlim = c(1e-1, 1e4)
) #-> environmenteventsneutral
# ggplot2::ggsave(environmenteventsneutral, filename = "MNA-EventEnvironmentArrivalTimes-Overview.pdf", dpi = "retina", width = 11, height = 8)
All Events, By Number in Sequence, Overall Time
Events %>% dplyr::group_by(
    Simulation, Iter, Distance, 
    Modifier, ModIntensity, Environments, Space
) %>% dplyr::arrange(
    Times
) %>% dplyr::mutate(
    InterarrivalTime = Times - lag(Times), 
    Dynamic = !Neutral, 
    Sequence = cumsum(Neutral)
) %>% dplyr::group_by(
    Environment, Sequence
) %>% dplyr::mutate(
    EventInSequence = cumsum(Dynamic)
) %>% dplyr::filter(
    Space != "Ring"
) %>% ggplot2::ggplot(ggplot2::aes(
    x = InterarrivalTime,
    fill = factor(EventInSequence)
)
) + ggplot2::geom_density(
    alpha = 0.25
) + ggplot2::scale_fill_viridis_d(
  "Event #"
) + ggplot2::facet_grid(
    Modifier + ModIntensity ~ Space + Distance
) + ggplot2::scale_x_log10(
) + ggplot2::coord_cartesian(
  xlim = c(1e-1, 1e4),
  ylim = c(0, 2)
) # -> overalleventssequence
# ggplot2::ggsave(overalleventssequence, filename = "MNA-EventOverallArrivalTimes-Sequence.pdf", dpi = "retina", width = 11, height = 8)
All Events, By Neutral/Dynamics, Overall Time
Events %>% dplyr::group_by(
    Simulation, Iter, Distance, 
    Modifier, ModIntensity, Environments, Space
) %>% dplyr::arrange(
    Times
) %>% dplyr::mutate(
    InterarrivalTime = Times - lag(Times), 
    Dynamic = !Neutral, 
    Sequence = cumsum(Neutral)
) %>% dplyr::group_by(
    Environment, Sequence
) %>% dplyr::mutate(
    EventInSequence = cumsum(Dynamic)
) %>% dplyr::filter(
    Space != "Ring"
) %>% ggplot2::ggplot(ggplot2::aes(
    x = InterarrivalTime,
    fill = Neutral
)
) + ggplot2::geom_density(
    alpha = 0.25
) + ggplot2::scale_fill_viridis_d(
) + ggplot2::facet_grid(
    Modifier + ModIntensity ~ Space + Distance
) + ggplot2::scale_x_log10(
) + ggplot2::coord_cartesian(
  xlim = c(1e-1, 1e4)
) # -> overalleventsneutral
# ggplot2::ggsave(overalleventsneutral, filename = "MNA-EventOverallArrivalTimes-Overview.pdf", dpi = "retina", width = 11, height = 8)
Successful Events, By Number in Sequence, Time by Environment
ggplot2::ggplot(
    EventsSuccesses %>% dplyr::filter(
        Space != "Ring"
    ),
    ggplot2::aes(
        x = InterarrivalTime,
        fill = factor(EventInSequence)
    )
) + ggplot2::geom_density(
  alpha = 0.25
) + ggplot2::scale_fill_viridis_d(
  "Event #"
) + ggplot2::facet_grid(
    Modifier + ModIntensity ~ Space + Distance
) + ggplot2::scale_x_log10(
) + ggplot2::coord_cartesian(
  xlim = c(1e-1, 1e4),
  ylim = c(0, 2)
) #-> environmenteventssuccesssequence
# ggplot2::ggsave(environmenteventssuccesssequence, filename = "MNA-EventSuccessEnvironmentArrivalTimes-Sequence.pdf", dpi = "retina", width = 11, height = 8)
Successful Events, By Neutral/Dynamics, Time by Environment
ggplot2::ggplot(
    EventsSuccesses %>% dplyr::filter(
        Space != "Ring"
    ),
    ggplot2::aes(
        x = InterarrivalTime,
        fill = Neutral
    )
) + ggplot2::geom_density(
  alpha = 0.25
) + ggplot2::scale_fill_viridis_d(
) + ggplot2::facet_grid(
    Modifier + ModIntensity ~ Space + Distance
) + ggplot2::scale_x_log10(
) + ggplot2::coord_cartesian(
  xlim = c(1e-1, 1e4)
) #-> environmenteventssuccessneutral
# ggplot2::ggsave(environmenteventssuccessneutral, filename = "MNA-EventSuccessEnvironmentArrivalTimes-Overview.pdf", dpi = "retina", width = 11, height = 8)
Successful Events, By Number in Sequence, Overall Time
EventsSuccesses %>% dplyr::group_by(
    Simulation, Iter, Distance, 
    Modifier, ModIntensity, Environments, Space
) %>% dplyr::arrange(
    Times
) %>% dplyr::mutate(
    InterarrivalTime = Times - lag(Times), 
    Dynamic = !Neutral, 
    Sequence = cumsum(Neutral)
) %>% dplyr::group_by(
    Environment, Sequence
) %>% dplyr::mutate(
    EventInSequence = cumsum(Dynamic)
) %>% dplyr::filter(
    Space != "Ring"
) %>% ggplot2::ggplot(ggplot2::aes(
    x = InterarrivalTime,
    fill = factor(EventInSequence)
)
) + ggplot2::geom_density(
    alpha = 0.25
) + ggplot2::scale_fill_viridis_d(
  "Event #"
) + ggplot2::facet_grid(
    Modifier + ModIntensity ~ Space + Distance
) + ggplot2::scale_x_log10(
) + ggplot2::coord_cartesian(
  xlim = c(1e-1, 1e4),
  ylim = c(0, 2)
) # -> overalleventssuccesssequence
# ggplot2::ggsave(overalleventssuccesssequence, filename = "MNA-EventSuccessOverallArrivalTimes-Sequence.pdf", dpi = "retina", width = 11, height = 8)
Successful Events, By Neutral/Dynamics, Overall Time
EventsSuccesses %>% dplyr::group_by(
    Simulation, Iter, Distance, 
    Modifier, ModIntensity, Environments, Space
) %>% dplyr::arrange(
    Times
) %>% dplyr::mutate(
    InterarrivalTime = Times - lag(Times), 
    Dynamic = !Neutral, 
    Sequence = cumsum(Neutral)
) %>% dplyr::group_by(
    Environment, Sequence
) %>% dplyr::mutate(
    EventInSequence = cumsum(Dynamic)
) %>% dplyr::filter(
    Space != "Ring"
) %>% ggplot2::ggplot(ggplot2::aes(
    x = InterarrivalTime,
    fill = Neutral
)
) + ggplot2::geom_density(
    alpha = 0.25
) + ggplot2::scale_fill_viridis_d(
) + ggplot2::facet_grid(
    Modifier + ModIntensity ~ Space + Distance
) + ggplot2::scale_x_log10(
) + ggplot2::coord_cartesian(
  xlim = c(1e-1, 1e4)
) # -> overalleventssuccessneutral
# ggplot2::ggsave(overalleventssuccessneutral, filename = "MNA-EventSuccessOverallArrivalTimes-Overview.pdf", dpi = "retina", width = 11, height = 8)
LS0tCnRpdGxlOiAiTXVsdGlwbGUgTnVtZXJpY2FsIEFzc2VtYmx5IDIiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgY29kZV9mb2xkaW5nOiBoaWRlCi0tLQoKIyBTZWN0aW9ucyB7LnRhYnNldH0KCiMjIEFic3RyYWN0CgpQcmV2aW91c2x5LCBJIHNlbnQgYXJvdW5kIHNvbWUgaW1hZ2VzIGNvbXBhcmluZyB0aGUgYWxwaGEgZGl2ZXJzaXR5IHJlc3VsdHMgb2YgZWFjaCBydW4uClRoaXMgbWV0IHdpdGggZ2VuZXJhbCBhcHByb3ZhbCBhcyB3ZWxsIGFzIHF1ZXN0aW9ucyBpbmNsdWRpbmcgZ2FtbWEgZGl2ZXJzaXR5LCB0aGUgYnVyc3RpbmVzcyBvZiBhcnJpdmFscyAoY28tZXN0YWJsaXNobWVudCksIHRoZSBidXJzdGluZXNzIG9mIGV4dGluY3Rpb25zIChjby1leHRpbmN0aW9ucyksIGFuZCBjb21wYXJpc29ucyB3aXRoIHB1cmVseSBuZXV0cmFsIG1vZGVscyBvZiBhcnJpdmFsIGFuZCBleHRpbmN0aW9uLgo8IS0tIApRdWFzaS1lcXVpbGlicmlhIDwtPiBjb21wYXJpc29uIHdpdGggc2ltcGxlIGNvbG9uaXNhdGlvbi9leHRpbmN0aW9uLiBOb3Qgc3VyZSBzdGlsbCBob3cgdG8gZG8gdGhpcyB3aXRoIGNvbW11bml0eSBzdHJ1Y3R1cmUuIEkgdGhpbmsgb25lIGNvdWxkIGluIHByaW5jaXBsZSBoYXZlIGVhY2ggb2YgdGhlIDJeMTAwIHN5c3RlbXMgYW5hbHlzZWQgZm9yIHplcm9zIGFuZCBzdGFiaWxpdHkgaW4gTWF0aGVtYXRpY2EgYW5kIHNlZSBob3cgdGhhdCBuYXZpZ2F0ZXMgdGhlIDJeMTAwIHN0YXRlIHNwYWNlLgpWYXJ5aW5nIHNwYWNlIDwtPiBjbGVhciBzaWduYWw/CgoKLS0+CgpJbiB0aGlzIGRvY3VtZW50LCB3ZSBjb250aW51ZSB0byBhdHRlbXB0IHRvIGFkZHJlc3MgQ2hyaXMncyBxdWVzdGlvbiBvZiBob3cgaW5jcmVhc2VkIHNwYXRpYWwgbW9iaWxpdHkgY2hhbmdlcyBiaW9kaXZlcnNpdHkgCm1lYXN1cmVzLiA8IS0tV2hhdCBxdWVzdGlvbiB0byBhZGRyZXNzLi0tPgpXZSBiZWdpbiBieSBsb2FkaW5nIHVwIGVhY2ggZGF0YSBzZXQgcmVmZXJyaW5nIHRvIGRpZmZlcmVudCBuZXV0cmFsIChhcnJpdmFsLWV4dGluY3Rpb24pIGFuZCBzcGF0aWFsIChkaXNwZXJzYWwgc3BlZWQpIGNvbmRpdGlvbnMuIApXZSBjYW4gdGhlbiBleHRyYWN0IG91ciBkaXZlcnNpdHkgbWV0cmljcyBmb3IgZWFjaCBzeXN0ZW0gYW5kIGVhY2ggc2l0ZS9lY29zeXN0ZW0vZW52aXJvbm1lbnQgd2l0aGluIHRoZSBzeXN0ZW0gYW5kIGNvbXBhcmUgdGhlbS4KCiMjIyBOb3RlcwoKKiBXaGlsZSBDaHJpcyBwcmVmZXJzIGFidW5kYW5jZS9yaWNobmVzcyBhcyBhIGRpY2hvdG9teSwgaXQgbWlnaHQgYmUgaGVscGZ1bCBmb3IgcHVibGljYXRpb24gdG8gY29uc2lkZXIgbW9yZSB0aGFuIHRoYXQuCgojIyMgVE9ETwoKKiBNZWFzdXJlIHRoZSBpbXBhY3Qgb2YgZGlzcGVyc2FsIG9uIGludmFkYWJpbGl0eS4gVGhpcyBwcmVmZXJhYmx5IGlkZW50aWZpZXMgYm90aCB0aGUgaGVpZ2h0IG9mIHRoZSBuZXcgYmFycmllciBhcyB3ZWxsIGFzIHByZWNpc2VseSBkZXRlcm1pbmluZyB0aGUgZWZmZWN0LiBUaGlzIG1pZ2h0IGluY2x1ZGUgdGhlIGFzeW1tZXRyeSBhdCB0aGUgZW5kcyBvZiB0aGUgbGluZSBzcGF0aWFsIGFycmFuZ2VtZW50IChhcyBjb21wYXJlZCB0byBhIHJpbmcgc3BhdGlhbCBhcnJhbmdlbWVudCkuCioqIEkgYW50aWNpcGF0ZSB0aGF0IHRoaXMgaXMgcHJlY2lzZWx5IHRoZSBlZmZlY3Qgb2YgdGhlIGV4dHJhIHRlcm0uIFRvIHNob3cgaXQgdGhlbiwgYW5hbHl0aWNhbGx5IHdlIGNhbiBjaGVjayB0aGUgcGVyLWNhcGl0YSByYXRlIG9mIGdyb3d0aCB3aXRoIHRoZSBhZGRpdGlvbmFsIHRlcm0sIHdoaWNoIHdpbGwgYWN0IGFzIGEgcGVuYWx0eS4gRW1waXJpY2FsbHksIHdlIGxvb2sgYXQgdGhlIGludmFzaW9ucyB0aGF0IHdlIGV4cGVjdCB0byBoYXZlIHN1Y2NlZWRlZCBidXQgdGhlbiBkaWVkIG91dCB3aGVuIHNwYWNlIHdhcyBpbnRyb2R1Y2VkIGFuZCB3ZSBzaG91bGQgYmUgYWJsZSB0byBzZWUgYSBnb29kIG1hdGNoIGJldHdlZW4gaXRzIHByZWRpY3RlZCBwZXItY2FwaXRhIGdyb3d0aCByYXRlIGFuZCB3aGVuL2lmIGl0IGRpZWQgb3V0IHdpdGhpbiBhIGdpdmVuIHN5c3RlbS4gVGhpcyBicmVha3MgZG93biBpZiBpdCBjYW4gc3Vydml2ZSBpbiBhbiBhZGphY2VudCBzeXN0ZW0sIGZvciB3aGF0IGl0IGlzIHdvcnRoLgoqIEV2ZW5uZXNzIGJ5IHRyb3BoaWMgbGV2ZWwuIFRoaXMgbWlnaHQgaGVscCB1cyBkZWR1Y2UgaG93IG5ldXRyYWwgdGhlIHRyb3BoaWMgbGV2ZWxzIGFyZSwgYnV0IHJlcXVpcmVzIGFuYWx5c2luZyBob3cgdGhlIHRyb3BoaWMgbmV0d29yayBjaGFuZ2VzIG92ZXIgdGltZSAocG9zc2libHkgaW4gY29udHJhc3QgdG8gdGhlIHRoZW9yZXRpY2FsIGZvb2Qgd2ViKS4gRnVydGhlcm1vcmUsIHRoaXMgaXMgbW9zdCBhZHZhbnRhZ2VvdXMgdG8gaW52ZXN0aWdhdGUgYXMgd2UgY2hhbmdlIHRoZSBwYXJhbWV0ZXJzIG9mIHRoZSBzaW11bGF0aW9uIHRvIGluY2x1ZGUgbW9yZSB0cm9waGljIGxldmVscy4gVGhpcyB3b3VsZCBhbHNvIGFsbG93IHVzIHRvIGNvbG9yIGNvZGUgYWJ1bmRhbmNlIGFuZCBleGFtaW5lIHJpY2huZXNzIG9mIHRyb3BoaWMgbGV2ZWxzIChib3RoIG51bWJlciBvZiBsZXZlbHMgYW5kIHJpY2huZXNzIHdpdGhpbiBsZXZlbHMpLgoqKiBXZSBzaG91bGQgbWFrZSBhIHBvaW50IG9mIHJ1bm5pbmcgYW5vdGhlciBsYXllciBvZiBjb25zdW1lcnMgKGFuZCBwcm9kdWNlcnM/KSBhcyB3ZWxsIHNvIGFzIHRvIGJlIGFibGUgdG8gYmV0dGVyIG9ic2VydmUgdGhlIHJlc3VsdGFudCBkaXZlcnNpdHkuIEkgZG8gbm90ZSB0aGF0LCBjb250cmFyeSB0byBwcmV2aW91cyBleHBlY2F0aW9ucywgd2UgYXJlIHJ1bm5pbmcgYXQgYWJvdXQgJDMwXCUkIG9mIHRoZSBwb29sLiBBcyBJIGFtIG9ubHkgdXNpbmcgMSBwb29sIGF0IHRoaXMgcG9pbnQsIHRoZXJlIG1pZ2h0IGJlIGEgaGlnaCBhbW91bnQgb2YgdmFyaWF0aW9uLgoqKiBUaGUgcGFyZW50IHBvaW50IGhlcmUgbWlnaHQgcmVxdWlyZSBtb3Zpbmcgb250byBWaWtpbmcuIFRoZSBgZGVTb2x2ZWAgcGFja2FnZSBkb2VzIGhhdmUgZnVuY3Rpb25zIHRoYXQgcmV0dXJuIGxpc3RzLCB3aGVyZSB0aGUgZmlyc3QgZWxlbWVudCBpcyBhIHZlY3RvciBvZiBkZXJpdmF0aXZlcyBvZiAkeSQgd2l0aCByZXNwZWN0IHRvICR0JC4gVGhlICcnbmV4dCcnIGVsZW1lbnRzIHNlZW0gbGlrZSB0aGV5IGNvdWxkIGJlIHRoaW5ncyBsaWtlIHRoZSB0cm9waGljIHN0cnVjdHVyZSBhbmQgdHJvcGhpYyBsZXZlbHMuCiogV2Ugc2hvdWxkIGNvbnNpZGVyIHRoZSAicnVuIHRvIHN0YWJpbGl0eSIsIHRoZW4gdmFyaWFibGUgY2hhbmdlLiBUaGlzIHJlcXVpcmVzIGFub3RoZXIgc2V0IG9mICgyIHNldHMgb2YpIHN5c3RlbXMgd2hlcmUgd2UgcnVuIHRoZSBzeXN0ZW0gYXMgYmVmb3JlIHRvIHN0YWJpbGl0eSAoZXZlcnl0aGluZyBsb29rcyBzdGFibGUgYXQgbGVhc3QhKSBhbmQgdGhlbiBtYWtlIGEganVtcCBpbiBvbmUgKG9yIHR3bz8gc3BhY2UgYW5kIGFycml2YWwgb3Igc3BhY2UgYW5kIGV4dGluY3Rpb24gcmF0ZT8pIG9mIHRoZSBwYXJhbWV0ZXJzLgoqIEZyb20gcHJldmlvdXMgY2hhdHMsIHRoZXJlIGlzIGFsc28gdGhlIHByb3NwZWN0IG9mIGNvbXBhcmluZyAnJ3B1cmUnJyBuZXV0cmFsIGR5bmFtaWNzLiBJbiB0ZXJtcyBvZiBzaW11bGF0aW9ucywgYSBwb29sIG9mIHRoZSBzYW1lIHNpemUsIGJ1dCBhbGwgcHJvZHVjZXJzIHdvdWxkIHNlZW0gdG8gZG8gaXQuIEluIHRlcm1zIG9mIGFuYWx5dGljcywgdGhlcmUgc2hvdWxkIGJlIGEgZ29vZCBuZXV0cmFsIHRoZW9yeSBzb2x1dGlvbi4KKiBBbm90aGVyIHBvaW50IG9mIGludGVyZXN0IGlzIGhvdyBidXJzdHkgaXMgdGhlIGRpc3RyaWJ1dGlvbiBjb21wYXJlZCB0byB0aGUgZXhwb25lbnRpYWwgbnVsbCBtb2RlbD8gVGhpcyBpbiBlZmZlY3Qgc3R1ZGllcyB0aGUgaW1wYWN0IG9mIHRoZSBkeW5hbWljcy4gSWYgdGhleSBhcmUgZmFyIGJ1cnN0aWVyIHRoYW4gd2UgZXhwZWN0L25ldXRyYWxpdHkgd291bGQgZGljdGF0ZSwgdGhhbiB3ZSBjYW4gZGVkdWNlIHRoZXJlIGFyZSBtdWx0aXBsZSByZWxhdGVkIHNlY29uZGFyeSBleHRpbmN0aW9ucy4gT3RoZXJ3aXNlLCB0aGUgc3lzdGVtIHdvdWxkIGFwcGVhciB0byBiZSBtZXJlbHkgbmV1dHJhbCBkeW5hbWljcyBhbmQgcHJpbWFyeSBleHRpbmN0aW9ucy4KCgojIyMgRnV0dXJlCgoqIE9uY2UgdGhlIHN0cmljdGx5IGRldGVybWluaXN0aWMgZHluYW1pY3MgYXJlIHN1ZmZpY2llbnRseSBjbGVhcmVkIG91dCwgQ2hyaXMgKGFuZCBTdXNhbikgd291bGQgbGlrZSB0byBzd2FwIHRvIEdpbGxlc3BpZSBzdHlsZSAvIGp1bXAgcHJvY2VzcyAvIHN0b2NoaW9tZXRyeSBkeW5hbWljcy4KCiMjIyBGdW5jdGlvbnMKYGBge3IsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkoZHBseXIpICAgICAgICAjIERhdGEgTWFuaXB1bGF0aW9uCmxpYnJhcnkodGlkeXIpICAgICAgICAjIERhdGEgUGl2b3R0aW5nCmxpYnJhcnkoZ2dwbG90MikgICAgICAjIDItRCBQbG90CmxpYnJhcnkocGxvdGx5KSAgICAgICAjIDMtRCBQbG90CmxpYnJhcnkoZ2dmb3J0aWZ5KSAgICAjIHVzZWQgZm9yIGJpcGxvdHMgb2YgUENBcwpsaWJyYXJ5KHZlZ2FuKSAgICAgICAgIyBFY29sb2dpY2FsIGFuYWx5c2lzIG1lZ2EtcGFja2FnZQpsaWJyYXJ5KGh0bWx0b29scykgICAgIyBQcm9ncmFtbWF0aWMgY2h1bmtzCmxpYnJhcnkoZml0ZGlzdHJwbHVzKSAjIEFkdmFuY2VkIGZpdHRpbmcgb3ZlciBNQVNTLgpsaWJyYXJ5KHBvd2VSbGF3KSAgICAgIyBGaXR0aW5nIGhlYXZ5LXRhaWxlZCBkaXN0cmlidXRpb25zLgpsaWJyYXJ5KFJNVFJDb2RlMikgICAgIyBQZXJzb25hbCBwYWNrYWdlLgoKIyBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL2EvNzE3MjgzMgppZnJtIDwtIGZ1bmN0aW9uKG9iaiwgZW52ID0gZ2xvYmFsZW52KCkpIHsKICBvYmogPC0gZGVwYXJzZShzdWJzdGl0dXRlKG9iaikpCiAgaWYoZXhpc3RzKG9iaiwgZW52aXIgPSBlbnYpKSB7CiAgICBybShsaXN0ID0gb2JqLCBlbnZpciA9IGVudikKICB9Cn0KCmxvZzAgPC0gZnVuY3Rpb24oeCwgYmFzZSA9IGV4cCgxKSkgewogIHhuZXEwIDwtIHggIT0gMCAmICFpcy5uYSh4KQogIHhbeG5lcTBdIDwtIGxvZyh4W3huZXEwXSwgYmFzZSA9IGJhc2UpCiAgcmV0dXJuKHgpCn0KYGBgCgojIyMgRGF0YQoKQXMgb2YgdGhlIHdyaXRpbmcgb2YgdGhpcyBzY3JpcHQsIGFsbCBvZiB0aGUgZGF0YSBpcyBzdG9yZWQgaW4gdGhlIHNhbWUgbG9jYXRpb24gYXMgdGhpcyBzY3JpcHQuClRoZSBwYXJhbWV0ZXJzIHVzZWQgdG8gZ2VuZXJhdGUgdGhlIGludGVyYWN0aW9uIG1hdHJpY2VzLCBwb29scywgYW5kIGV2ZW50cyBpcyBub3Qgc3RvcmVkIHdpdGggdGhlIGF0dGVtcHRzLCB3aGljaCBpcyBzb21ldGhpbmcgSSBzaG91bGQgcHJvYmFibHkgZml4IGluIHRoZSBmdXR1cmUuCihJIGNvdWxkIHN0b3JlIHRoZW0gaW4gdGhlIGVsbGlwc2lzIGFyZ3VtZW50IG9yIGFzIGEgc2VwYXJhdGUgb2JqZWN0LikKYGBge3J9CmJ5X2Zvcl90aGlubmluZyA8LSAxMCAjIHRpbWUgc3RlcHMKZGl2aWRlX3RpbWVfYnkgPC0gMUU0ICMgdGltZSB1bml0cwpidXJuX2luIDwtIDFFNCAjIHRpbWUgdW5pdHMKCmxvYWRfc2FmZV90aGluIDwtIGZ1bmN0aW9uKGZuYW1lLCBieXRoaW4sIGRpdnRpbWUsIGJ1cm4pIHsKICBsb2FkZWQgPC0gdHJ5Q2F0Y2goe2xvYWQoZm5hbWUpfSwgCiAgICAgICAgICAgICAgICAgICAgIGVycm9yID0gZnVuY3Rpb24oZSkgewogICAgICAgICAgICAgICAgICAgICAgIHByaW50KGZuYW1lKQogICAgICAgICAgICAgICAgICAgICAgIHByaW50KGUpCiAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuKE5BKQogICAgICAgICAgICAgICAgICAgICB9KQogIGlmIChpcy5uYShsb2FkZWQpKSB7CiAgICByZXR1cm4oTkEpCiAgfSBlbHNlIHsKICAgIGxvYWRlZCA8LSBnZXQobG9hZGVkKQogICAgbG9hZGVkJEFidW5kYW5jZSA8LSBsb2FkZWQkQWJ1bmRhbmNlW3NlcShmcm9tID0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG8gPSBucm93KGxvYWRlZCRBYnVuZGFuY2UpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9IGJ5dGhpbiksIF0KICAgIAogICAgdG9FbGltaW5hdGUgPC0gbG9hZGVkJEFidW5kYW5jZVssIC0xXSA8IGxvYWRlZCRQYXJhbWV0ZXJzJEVsaW1pbmF0aW9uVGhyZXNob2xkICYgbG9hZGVkJEFidW5kYW5jZVssIC0xXSA+IDAKICAgIGxvYWRlZCRBYnVuZGFuY2VbLCAtMV1bdG9FbGltaW5hdGVdIDwtIDAKICAgIAogICAgbG9hZGVkJEFidW5kYW5jZSA8LSBsb2FkZWQkQWJ1bmRhbmNlWwogICAgICBsb2FkZWQkQWJ1bmRhbmNlWywgMV0gPiBidXJuLAogICAgXQogICAgCiAgICBsb2FkZWQkQWJ1bmRhbmNlWywgMV0gPC0gbG9hZGVkJEFidW5kYW5jZVssIDFdIC8gZGl2dGltZQogICAgcmV0dXJuKGxvYWRlZCkKICB9Cn0KCiMgQWxsIC5SRGF0YQpmaWxlc19kYXQgPC0gZGlyKHBhdHRlcm4gPSAiLlJEYXRhJCIpCiMgUmVtb3ZlIFBvb2xNYXRzCmZpbGVzX2RhdCA8LSBmaWxlc19kYXRbCiAgIWdyZXBsKHggPSBmaWxlc19kYXQsIAogICAgICAgICBwYXR0ZXJuID0gIlBvb2xNYXRzIiwgCiAgICAgICAgIGZpeGVkID0gVFJVRSkKICBdCgojIFRlY2huaWNhbGx5IG92ZXJraWxsLCBidXQgcHJldmVudHMgdW5pbnRlbnRpb25hbCBsb2Fkcy4KIyBCcmVhayBpbnRvIHR3byBzZXBhcmF0ZSBydW5zIHRvIGxvYWQgb25seSBpbnRlbmRlZC4KIyBQcm9jZXNzICJNTkEtRmlyc3RBdHRlbXB0IyMjIyMtUmVzdWx0LUVudjEwLSMjIyMuUkRhdGEiCmZpbGVzX2RhdF9GQSA8LSBmaWxlc19kYXRbCiAgZ3JlcGwoeCA9IGZpbGVzX2RhdCwgCiAgICAgICAgcGF0dGVybiA9ICJGaXJzdEF0dGVtcHQiLCAKICAgICAgICBmaXhlZCA9IFRSVUUpCiAgXQpSZXN1bHRzIDwtIHNhcHBseSgKICBmaWxlc19kYXRfRkEsCiAgbG9hZF9zYWZlX3RoaW4sIAogIGJ5dGhpbiA9IGJ5X2Zvcl90aGlubmluZywKICBkaXZ0aW1lID0gZGl2aWRlX3RpbWVfYnksIAogIGJ1cm4gPSBidXJuX2luLAogIHNpbXBsaWZ5ID0gRkFMU0UsIFVTRS5OQU1FUyA9IFRSVUUKKQoKIyBQcm9jZXNzICJNTkEtRGlzdCMjIyMjLUV4dCMjIy1FbnYxMC0jIyMjLlJEYXRhIgpmaWxlc19kYXRfRXh0IDwtIGZpbGVzX2RhdFsKICBncmVwbCh4ID0gZmlsZXNfZGF0LCAKICAgICAgICBwYXR0ZXJuID0gIkRpc3QiLCAKICAgICAgICBmaXhlZCA9IFRSVUUpCiAgXQpSZXN1bHRzIDwtIGMoUmVzdWx0cywgc2FwcGx5KAogIGZpbGVzX2RhdF9FeHQsCiAgbG9hZF9zYWZlX3RoaW4sIAogIGJ5dGhpbiA9IGJ5X2Zvcl90aGlubmluZywgCiAgZGl2dGltZSA9IGRpdmlkZV90aW1lX2J5LCAKICBidXJuID0gYnVybl9pbiwKICBzaW1wbGlmeSA9IEZBTFNFLCBVU0UuTkFNRVMgPSBUUlVFCikpCmBgYAoKIyMjIFBvb2xzIGFuZCBNYXRyaWNlcwoKYGBge3J9CmxvYWRfc2FmZSA8LSBmdW5jdGlvbihmbmFtZSkgewogIGxvYWRlZCA8LSB0cnlDYXRjaCh7bG9hZChmbmFtZSl9LCAKICAgICAgICAgICAgICAgICAgICAgZXJyb3IgPSBmdW5jdGlvbihlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgcHJpbnQoZm5hbWUpCiAgICAgICAgICAgICAgICAgICAgICAgcHJpbnQoZSkKICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4oTkEpCiAgICAgICAgICAgICAgICAgICAgIH0pCiAgaWYgKGFsbChpcy5uYShsb2FkZWQpKSkgewogICAgcmV0dXJuKE5BKQogIH0gZWxzZSB7CiAgICByZXR1cm4oc2FwcGx5KGxvYWRlZCwgZ2V0LCAKICAgICAgICAgICAgICAgICAgZW52aXIgPSBzeXMuZnJhbWUoc3lzLnBhcmVudCgwKSksIAogICAgICAgICAgICAgICAgICBzaW1wbGlmeSA9IEZBTFNFLCBVU0UuTkFNRVMgPSBUUlVFKSkKICB9Cn0KCiMgQWxsIC5SRGF0YQpmaWxlc19kYXRfUE0gPC0gZGlyKHBhdHRlcm4gPSAiLlJEYXRhJCIpCiMgUmVtb3ZlIFBvb2xNYXRzCmZpbGVzX2RhdF9QTSA8LSBmaWxlc19kYXRfUE1bCiAgZ3JlcGwoeCA9IGZpbGVzX2RhdF9QTSwgCiAgICAgICAgcGF0dGVybiA9ICJQb29sTWF0cyIsIAogICAgICAgIGZpeGVkID0gVFJVRSkKICBdCgpQb29sc01hdHMgPC0gc2FwcGx5KAogIGZpbGVzX2RhdF9QTSwKICBsb2FkX3NhZmUsIAogIHNpbXBsaWZ5ID0gRkFMU0UsIFVTRS5OQU1FUyA9IFRSVUUKKQpgYGAKCiMjIyBUcm9waGljIEZ1bmN0aW9ucwpgYGB7cn0KRWxpbWluaWF0aW9uVGhyZXNob2xkIDwtIHVuaXF1ZShzYXBwbHkoCiAgUmVzdWx0cywgCiAgZnVuY3Rpb24obHN0KSB7bHN0JFBhcmFtZXRlcnMkRWxpbWluYXRpb25UaHJlc2hvbGR9CikpCnN0b3BpZm5vdChsZW5ndGgoRWxpbWluaWF0aW9uVGhyZXNob2xkKSA9PSAxKQoKTnVtRW52aXJvbm1lbnRzIDwtIHVuaXF1ZShzYXBwbHkoCiAgUmVzdWx0cywgCiAgZnVuY3Rpb24obHN0KSB7bHN0JE51bUVudmlyb25tZW50c30KKSkKc3RvcGlmbm90KGxlbmd0aChOdW1FbnZpcm9ubWVudHMpID09IDEpCgpUcm9waGljRnVuY3Rpb25zIDwtIHNhcHBseSgKICBQb29sc01hdHMsCiAgZnVuY3Rpb24oUE0sIE5FLCBFVCkgewogICAgUk1UUkNvZGUyOjpDYWxjdWxhdGVUcm9waGljU3RydWN0dXJlKAogICAgICBQb29sID0gUE0kUG9vbCwKICAgICAgTnVtRW52aXJvbm1lbnRzID0gTkUsCiAgICAgIEludGVyYWN0aW9uTWF0cmljZXMgPSBQTSRJbnRlcmFjdGlvbk1hdHJpY2VzLAogICAgICBFbGltaW5hdGlvblRocmVzaG9sZCA9IEVUCiAgICApCiAgfSwKICBORSA9IE51bUVudmlyb25tZW50cywKICBFVCA9IEVsaW1pbmlhdGlvblRocmVzaG9sZAopCmBgYAoKYGBge3IsIHdhcm5pbmc9RkFMU0UsIGV2YWw9RkFMU0V9CiNUT0RPIEZpeCB3YXJuaW5nIChiaW5kaW5nIGNoYXJhY3RlciBhbmQgZmFjdG9yIHZlY3RvciwgY29lcmNpbmcgaW50byBjaGFyYWN0ZXIgdmVjdG9yIGluIGJpbmRfcm93cykKVHJvcGhpY0FuYWx5c2VzIDwtIGxpc3QoKQpSZXN1bHQgPSBSZXN1bHRzCk5tID0gbmFtZXMoUmVzdWx0cykKVHJvcGhGTiA9IFRyb3BoaWNGdW5jdGlvbnMKCmZvciAoaSBpbiBzZXFfYWxvbmcoUmVzdWx0cykpIHsKICBwcmludChpKTsgcHJpbnQoTm1baV0pCiAgIyBJZGVudGlmeSBBcHByb3ByaWF0ZSBGdW5jdGlvbi4KICBVbnVzdWFsMSA8LSBncmVwbChwYXR0ZXJuID0gIkZpcnN0QXR0ZW1wdCIsCiAgICAgICAgICAgICAgICAgICAgeCA9IE5tW2ldLCBmaXhlZCA9IFRSVUUpCiAgTm9ybWFsS2V5IDwtIHN0cnNwbGl0KE5tW2ldLCBzcGxpdCA9ICctJylbWzFdXVszXQogIGxpbmtlZEZOIDwtIGlmKFVudXN1YWwxKSB7CiAgICBUcm9waEZOW2dyZXBsKHggPSBuYW1lcyhUcm9waEZOKSwKICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICJGaXJzdEF0dGVtcHQiLCBmaXhlZCA9IFRSVUUpXVtbMV1dCiAgfSBlbHNlIHsKICAgIFRyb3BoRk5bZ3JlcGwoeCA9IG5hbWVzKFRyb3BoRk4pLAogICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gTm9ybWFsS2V5LCBmaXhlZCA9IFRSVUUpXVtbMV1dCiAgfQogIAogICMgQXBwbHkgdG8gZWFjaCByb3cuCiAgCiAgVHJvcGhpY0FuYWx5c2VzW1tpXV0gPC0gYXBwbHkoUmVzdWx0W1tpXV0kQWJ1bmRhbmNlWywgLTFdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1BUkdJTiA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlVOID0gbGlua2VkRk4pCn0KCiMgVHJvcGhpY0FuYWx5c2VzIDwtIGxhcHBseSgKIyAgIHNlcV9hbG9uZyhSZXN1bHRzKSwKIyAgIGZ1bmN0aW9uKGksIFJlc3VsdCwgTm0sIFRyb3BoRk4pIHsKIyAgICAgIyBJZGVudGlmeSBBcHByb3ByaWF0ZSBGdW5jdGlvbi4KIyAgICAgVW51c3VhbDEgPC0gZ3JlcGwocGF0dGVybiA9ICJGaXJzdEF0dGVtcHQiLAojICAgICAgICAgICAgICAgICAgICAgICB4ID0gTm1baV0sIGZpeGVkID0gVFJVRSkKIyAgICAgTm9ybWFsS2V5IDwtIHN0cnNwbGl0KE5tW2ldLCBzcGxpdCA9ICctJylbWzFdXVszXQojICAgICBsaW5rZWRGTiA8LSBpZihVbnVzdWFsMSkgewojICAgICAgIFRyb3BoRk5bZ3JlcGwoeCA9IG5hbWVzKFRyb3BoRk4pLAojICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiRmlyc3RBdHRlbXB0IiwgZml4ZWQgPSBUUlVFKV1bWzFdXQojICAgICB9IGVsc2UgewojICAgICAgIFRyb3BoRk5bZ3JlcGwoeCA9IG5hbWVzKFRyb3BoRk4pLCAKIyAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gTm9ybWFsS2V5LCBmaXhlZCA9IFRSVUUpXVtbMV1dCiMgICAgIH0KIyAgICAgCiMgICAgICMgQXBwbHkgdG8gZWFjaCByb3cuCiMgICAgIAojICAgICByZXR1cm4oYXBwbHkoUmVzdWx0W1tpXV0kQWJ1bmRhbmNlWywgLTFdLAojICAgICAgICAgICAgICAgICAgTUFSR0lOID0gMSwKIyAgICAgICAgICAgICAgICAgIEZVTiA9IGxpbmtlZEZOKQojICAgICApCiMgICB9LAojICAgUmVzdWx0ID0gUmVzdWx0cywKIyAgIE5tID0gbmFtZXMoUmVzdWx0cyksCiMgICBUcm9waEZOID0gVHJvcGhpY0Z1bmN0aW9ucwojICkKCm5hbWVzKFRyb3BoaWNBbmFseXNlcykgPC0gbmFtZXMoUmVzdWx0cykKYGBgCgojIyBEaXZlcnNpdHkgey50YWJzZXR9CgojIyMgUHJlcGFyYXRpb24KYGBge3J9CiMgQm9ycm93aW5nIGNvZGUgZnJvbSBGaXJzdEF0dGVtcHQtRG9jLUFuYWx5c2lzLlJtZApDYWxjdWxhdGVfRGl2ZXJzaXR5IDwtIGZ1bmN0aW9uKHJlc3VsdCkgewogIERpdmVyc2l0eSA8LSBsYXBwbHkoCiAgICAxOnJlc3VsdCROdW1FbnZpcm9ubWVudHMsCiAgICBmdW5jdGlvbihpLCBhYnVuZCwgbnVtU3BlY2llcykgewogICAgICB0aW1lIDwtIGFidW5kWywgMV0KICAgICAgZW52IDwtIGFidW5kWywgMSArIDE6bnVtU3BlY2llcyArIG51bVNwZWNpZXMgKiAoaSAtIDEpXQogICAgICByaWNobmVzcyA8LSByb3dTdW1zKGVudiAhPSAwKQogICAgICBhYnVuZFN1bSA8LSByb3dTdW1zKGVudikKICAgICAgI05PVEU6IFRISVMgQ0FOIFlJRUxEIE5BTidTICgwLzApLgogICAgICAjIFRISVMgSVMgTk9UIE5FQ0VTU0FSSUxZIEEgUFJPQkxFTS4KICAgICAgIyBJVCBNSUdIVCBCRSBXT1JUSCBJVCBKVVNUIFRPIFVTRSAwIE9SCiAgICAgICMgVE8gQ0FUQ0ggSVQgRVhQTElDSVRMWSBBTkQgUkVQTEFDRSBXSVRIIE5BTi4KICAgICAgZW50cm9weSA8LSBlbnYgLyBhYnVuZFN1bQogICAgICBlbnRyb3B5IDwtIC0gYXBwbHkoCiAgICAgICAgZW50cm9weSwgTUFSR0lOID0gMSwKICAgICAgICBGVU4gPSBmdW5jdGlvbih4KSB7CiAgICAgICAgICBzdW0oeCAqIGxvZzAoeCkpCiAgICAgICAgfSkKICAgICAgc3BlY2llcyA8LSBhcHBseSgKICAgICAgICBlbnYsIE1BUkdJTiA9IDEsCiAgICAgICAgRlVOID0gZnVuY3Rpb24oeCkgewogICAgICAgICAgdG9TdHJpbmcod2hpY2goeCA+IDApKQogICAgICAgIH0KICAgICAgKQogICAgICBldmVubmVzcyA8LSBlbnRyb3B5IC8gbG9nKHJpY2huZXNzKQogICAgICBkYXRhLmZyYW1lKFRpbWUgPSB0aW1lLCAKICAgICAgICAgICAgICAgICBSaWNobmVzcyA9IHJpY2huZXNzLCAKICAgICAgICAgICAgICAgICBFbnRyb3B5ID0gZW50cm9weSwKICAgICAgICAgICAgICAgICBFdmVubmVzcyA9IGV2ZW5uZXNzLAogICAgICAgICAgICAgICAgIFNwZWNpZXMgPSBzcGVjaWVzLAogICAgICAgICAgICAgICAgIEVudmlyb25tZW50ID0gaSwKICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCiAgICB9LAogICAgYWJ1bmQgPSByZXN1bHQkQWJ1bmRhbmNlLAogICAgbnVtU3BlY2llcyA9IChuY29sKHJlc3VsdCRBYnVuZGFuY2UpIC0gMSkgLyByZXN1bHQkTnVtRW52aXJvbm1lbnRzCiAgKQogIAogIAogIERpdmVyc2l0eSA8LSBkcGx5cjo6YmluZF9yb3dzKERpdmVyc2l0eSkKICBEaXZlcnNpdHlfYWxwaGEgPC0gRGl2ZXJzaXR5CiAgIyBEaXZlcnNpdHlfYWxwaGEgPC0gRGl2ZXJzaXR5X2FscGhhICU+JSBkcGx5cjo6bXV0YXRlKAogICMgICBFdmVubmVzcyA9IEVudHJvcHkgLyBsb2coUmljaG5lc3MpCiAgIyApCiAgCiAgIyBNb2RpZnkgdG8gZG8gdGhlIGdhbW1hIGJpdHMgcmlnaHQgaGVyZS4KICBEaXZlcnNpdHlfZ2FtbWEgPC0gRGl2ZXJzaXR5ICU+JSBkcGx5cjo6Z3JvdXBfYnkoCiAgICBUaW1lCiAgKSAlPiUgZHBseXI6OnN1bW1hcmlzZSgKICAgIE1lYW4gPSBtZWFuKFJpY2huZXNzKSwKICAgIFNwZWNpZXNUb3RhbCA9IHRvU3RyaW5nKHNvcnQodW5pcXVlKHVubGlzdChzdHJzcGxpdChwYXN0ZSgKICAgICAgU3BlY2llcywgY29sbGFwc2UgPSAiLCAiKSwgc3BsaXQgPSAiLCAiLCBmaXhlZCA9IFRSVUUpKSkpKSwKICAgIEdhbW1hID0gdW5saXN0KGxhcHBseShzdHJzcGxpdCgKICAgICAgU3BlY2llc1RvdGFsLCBzcGxpdCA9ICIsICIsIGZpeGVkID0gVFJVRSksIGZ1bmN0aW9uKHgpIGxlbmd0aCh4W3ghPSIiXSkgKSkKICApICU+JSB0aWR5cjo6cGl2b3RfbG9uZ2VyKAogICAgY29scyA9IGMoTWVhbiwgR2FtbWEpLCAKICAgIG5hbWVzX3RvID0gIkFnZ3JlZ2F0aW9uIiwKICAgIHZhbHVlc190byA9ICJSaWNobmVzcyIKICApCiAgCiAgIyBDb21iaW5lIHRoZSB0d28gdHlwZXMgb2YgcmVzdWx0cwogIERpdmVyc2l0eV9hbHBoYSA8LSBEaXZlcnNpdHlfYWxwaGEgJT4lIGRwbHlyOjpzZWxlY3QoCiAgICAtU3BlY2llcwogICkgJT4lIHRpZHlyOjpwaXZvdF9sb25nZXIoCiAgICBjb2xzID0gYyhSaWNobmVzcywgRW50cm9weSwgRXZlbm5lc3MpLAogICAgbmFtZXNfdG8gPSAiTWVhc3VyZW1lbnQiLAogICAgdmFsdWVzX3RvID0gIlZhbHVlIgogICkgJT4lIGRwbHlyOjptdXRhdGUoCiAgICBFbnZpcm9ubWVudCA9IGFzLmNoYXJhY3RlcihFbnZpcm9ubWVudCkKICApCiAgCiAgRGl2ZXJzaXR5X2dhbW1hIDwtIERpdmVyc2l0eV9nYW1tYSAlPiUgZHBseXI6OnNlbGVjdCgKICAgIC1TcGVjaWVzVG90YWwKICApICU+JSBkcGx5cjo6cmVuYW1lKAogICAgRW52aXJvbm1lbnQgPSBBZ2dyZWdhdGlvbiwKICAgIFZhbHVlID0gUmljaG5lc3MKICApICU+JSBkcGx5cjo6bXV0YXRlKAogICAgTWVhc3VyZW1lbnQgPSAiUmljaG5lc3MiCiAgKQogIAogIERpdmVyc2l0eV9iZXRhIDwtIERpdmVyc2l0eV9hbHBoYSAlPiUgZHBseXI6OmZpbHRlcigKICAgIE1lYXN1cmVtZW50ID09ICJSaWNobmVzcyIKICApICU+JSBkcGx5cjo6c2VsZWN0KAogICAgLU1lYXN1cmVtZW50CiAgKSAlPiUgZHBseXI6OmxlZnRfam9pbigKICAgIHkgPSBEaXZlcnNpdHlfZ2FtbWEgJT4lIGRwbHlyOjpmaWx0ZXIoCiAgICAgIE1lYXN1cmVtZW50ID09ICJSaWNobmVzcyIsIEVudmlyb25tZW50ID09ICJHYW1tYSIKICAgICkgJT4lIGRwbHlyOjpzZWxlY3QoCiAgICAgIC1NZWFzdXJlbWVudCwgLUVudmlyb25tZW50CiAgICApLAogICAgYnkgPSAiVGltZSIsCiAgICBzdWZmaXggPSBjKCJfQWxwaGEiLCAiX0dhbW1hIikKICAgICMgKSAlPiUgZHBseXI6Omdyb3VwX2J5KAogICAgIyAgIFRpbWUKICApICU+JSBkcGx5cjo6bXV0YXRlKAogICAgQmV0YVNwZWNpZXNNaXNzaW5nID0gVmFsdWVfR2FtbWEgLSBWYWx1ZV9BbHBoYSwKICAgIEJldGFTcGVjaWVzUGVyY2VudGFnZSA9IFZhbHVlX0FscGhhL1ZhbHVlX0dhbW1hCiAgKSAlPiUgZHBseXI6OnNlbGVjdCgKICAgIC1WYWx1ZV9HYW1tYSwgLVZhbHVlX0FscGhhCiAgKSAlPiUgdGlkeXI6OnBpdm90X2xvbmdlcigKICAgIG5hbWVzX3RvID0gIk1lYXN1cmVtZW50IiwKICAgIHZhbHVlc190byA9ICJWYWx1ZSIsCiAgICBjb2xzID0gYyhCZXRhU3BlY2llc01pc3NpbmcsIEJldGFTcGVjaWVzUGVyY2VudGFnZSkKICAgICMgKSAlPiUgZHBseXI6OnVuZ3JvdXAoCiAgKQogIAogICNwcmludChjKGNvbG5hbWVzKERpdmVyc2l0eV9hbHBoYSksIGNvbG5hbWVzKERpdmVyc2l0eV9iZXRhKSwgY29sbmFtZXMoRGl2ZXJzaXR5X2dhbW1hKSkpCiAgRGl2ZXJzaXR5IDwtIHJiaW5kKAogICAgRGl2ZXJzaXR5X2FscGhhLAogICAgRGl2ZXJzaXR5X2JldGEsCiAgICBEaXZlcnNpdHlfZ2FtbWEKICApCiAgCiAgcmV0dXJuKERpdmVyc2l0eSkKfQoKRGl2ZXJzaXR5X2phY2NhcmRfc3BhY2UgPC0gZnVuY3Rpb24ocmVzdWx0KSB7CiAgYXBwbHkoCiAgICByZXN1bHQkQWJ1bmRhbmNlLAogICAgTUFSR0lOID0gMSwgIyBSb3dzCiAgICBmdW5jdGlvbihyb3csIGVudnMpIHsKICAgICAgdGltZSA8LSByb3dbMV0KICAgICAgZGlzdHMgPC0gdmVnYW46OnZlZ2Rpc3QoCiAgICAgICAgbWV0aG9kID0gImphY2NhcmQiLCAKICAgICAgICB4ID0gbWF0cml4KHJvd1stMV0gPiAwLCBucm93ID0gZW52cywgYnlyb3cgPSBUUlVFKQogICAgICApCiAgICAgIAogICAgICBkYXRhZiA8LSBleHBhbmQuZ3JpZCgKICAgICAgICBFbnYxID0gMTplbnZzLAogICAgICAgIEVudjIgPSAxOmVudnMKICAgICAgKSAlPiUgZHBseXI6OmZpbHRlcigKICAgICAgICBFbnYxIDwgRW52MgogICAgICApICU+JSBkcGx5cjo6bXV0YXRlKAogICAgICAgIFRpbWUgPSB0aW1lLAogICAgICAgIEphY2NhcmQgPSBkaXN0cwogICAgICApCiAgICAgIAogICAgICByZXR1cm4oZGF0YWYpCiAgICB9LAogICAgZW52cyA9IHJlc3VsdCROdW1FbnZpcm9ubWVudHMKICApCn0KCkRpdmVyc2l0eV9qYWNjYXJkX3RpbWUgPC0gZnVuY3Rpb24ocmVzdWx0LCBzdWJzYW1wbGUgPSAxMDApIHsKICAjIEJyZWFrIGludG8gZW52aXJvbm1lbnRzLCB0aGVuIGFwcGx5IGl0IHRvIHRoZSB0aW1lIHNlcmllcy4KICBwYXRjaGVzIDwtIGxhcHBseSgKICAgIDE6cmVzdWx0JE51bUVudmlyb25tZW50cywgZnVuY3Rpb24oaSwgYWJ1bmQsIGVudnMsIHNwZWMpIHsKICAgICAgYWJ1bmQgPC0gYWJ1bmRbc2VxKGZyb20gPSAxLCB0byA9IG5yb3coYWJ1bmQpLCBieSA9IHN1YnNhbXBsZSksIF0KICAgICAgdGltZXMgPC0gYWJ1bmRbLCAxXQogICAgICBwYXRjaCA8LSBhYnVuZFssIDEgKyAxOnNwZWMgKyBzcGVjICogKGkgLSAxKV0KICAgICAgCiAgICAgIGRpc3RzIDwtIHZlZ2FuOjp2ZWdkaXN0KAogICAgICAgIG1ldGhvZCA9ICJqYWNjYXJkIiwgCiAgICAgICAgeCA9IHBhdGNoID4gMAogICAgICApCiAgICAgIAogICAgICBkYXRhZiA8LSBleHBhbmQuZ3JpZCgKICAgICAgICBUaW1lMSA9IHRpbWVzLAogICAgICAgIFRpbWUyID0gdGltZXMKICAgICAgKSAlPiUgZHBseXI6OmZpbHRlcigKICAgICAgICBUaW1lMSA8IFRpbWUyCiAgICAgICkgJT4lIGRwbHlyOjptdXRhdGUoCiAgICAgICAgRW52aXJvbm1lbnQgPSBpLAogICAgICAgIEphY2NhcmQgPSBkaXN0cwogICAgICApCiAgICAgIAogICAgICByZXR1cm4oZGF0YWYpCiAgICB9LCBhYnVuZCA9IHJlc3VsdCRBYnVuZGFuY2UsIGVudnMgPSByZXN1bHQkTnVtRW52aXJvbm1lbnRzLAogICAgc3BlYyA9IChuY29sKHJlc3VsdCRBYnVuZGFuY2UpIC0gMSkgLyByZXN1bHQkTnVtRW52aXJvbm1lbnRzCiAgKQp9CmBgYAoKYGBge3IsIGV2YWw9VFJVRX0KQ2FsY3VsYXRlX1NwZWNpZXMgPC0gZnVuY3Rpb24ocmVzdWx0LCBiaW50aW1lcyA9IEZBTFNFKSB7CiAgU3BlY2llc1BlckVudmlyb25tZW50IDwtIGxhcHBseSgKICAgIDE6cmVzdWx0JE51bUVudmlyb25tZW50cywKICAgIGZ1bmN0aW9uKGksIGFidW5kLCBudW1TcGVjaWVzKSB7CiAgICAgIHRpbWUgPC0gYWJ1bmRbLCAxXQogICAgICBlbnYgPC0gYWJ1bmRbLCAxICsgMTpudW1TcGVjaWVzICsgbnVtU3BlY2llcyAqIChpIC0gMSldCiAgICAgICMgTmVlZCB0byByZXRyaWV2ZSBQb3NpdGlvbiBhbmQgVmFsdWUKICAgICAgc3BlY2llcyA8LSBhcHBseSgKICAgICAgICBjYmluZCh0aW1lLCBlbnYpLCBNQVJHSU4gPSAxLAogICAgICAgIEZVTiA9IGZ1bmN0aW9uKHgpIHsKICAgICAgICAgIHRpbWUgPC0geFsxXQogICAgICAgICAgZGF0IDwtIHhbLTFdCiAgICAgICAgICBpZiAoYW55KGRhdCA+IDApKSB7CiAgICAgICAgICAgIHBvc2l0aW9ucyA8LSAod2hpY2goZGF0ID4gMCkpCiAgICAgICAgICAgIHZhbHVlcyA8LSBkYXRbcG9zaXRpb25zXQogICAgICAgICAgICBkYXRhLmZyYW1lKAogICAgICAgICAgICAgIFRpbWUgPSB0aW1lLAogICAgICAgICAgICAgIFNwZWNpZXMgPSBwb3NpdGlvbnMsCiAgICAgICAgICAgICAgQWJ1bmRhbmNlID0gdmFsdWVzLAogICAgICAgICAgICAgIHJvdy5uYW1lcyA9IE5VTEwKICAgICAgICAgICAgKQogICAgICAgICAgfSBlbHNlIHtOVUxMfQogICAgICAgICAgIyBSZXR1cm5zIGFzIGxpc3QKICAgICAgICB9CiAgICAgICkKICAgICAgcmV0dXJuKAogICAgICAgIGRwbHlyOjpiaW5kX3Jvd3Moc3BlY2llcykgJT4lIGRwbHlyOjptdXRhdGUoCiAgICAgICAgICBFbnZpcm9ubWVudCA9IGkKICAgICAgICApCiAgICAgICkKICAgIH0sCiAgICBhYnVuZCA9IHJlc3VsdCRBYnVuZGFuY2UsCiAgICBudW1TcGVjaWVzID0gKG5jb2wocmVzdWx0JEFidW5kYW5jZSkgLSAxKSAvIHJlc3VsdCROdW1FbnZpcm9ubWVudHMKICApCiAgCiAgaWYgKGJpbnRpbWVzKSB7CiAgICAjIFNob3VsZCBlcXVhbGlzZSB0aW1lIHN0ZXBzLgogICAgU3BlY2llc1BlckVudmlyb25tZW50IDwtIGxhcHBseSgKICAgICAgU3BlY2llc1BlckVudmlyb25tZW50LCBmdW5jdGlvbihTUEUpIHsKICAgICAgICBTUEUgJT4lIGRwbHlyOjptdXRhdGUoCiAgICAgICAgICBUaW1lRmxvb3IgPSBmbG9vcihUaW1lKjEwKS8xMAogICAgICAgICkgJT4lIGRwbHlyOjpncm91cF9ieSgKICAgICAgICAgIFRpbWVGbG9vciwgU3BlY2llcywgRW52aXJvbm1lbnQKICAgICAgICApICU+JSBkcGx5cjo6c3VtbWFyaXNlKAogICAgICAgICAgQWJ1bmRhbmNlID0gbWVkaWFuKEFidW5kYW5jZSwgbmEucm0gPSBUUlVFKQogICAgICAgICkKICAgICAgfSkKICB9CiAgCiAgcmV0dXJuKGRwbHlyOjpiaW5kX3Jvd3MoU3BlY2llc1BlckVudmlyb25tZW50KSkKfQpgYGAKCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQojIE5vdGUgdGhhdCBpZiBhIGZpbGUgZmFpbHMgdG8gbG9hZCwgd2UgbWlnaHQgaGF2ZSBOQSBpbnN0ZWFkIG9mIGEgcmVzdWx0IHRvIHdvcmsgd2l0aC4KRGl2ZXJzaXR5IDwtIHNhcHBseSgKICBVU0UuTkFNRVMgPSBUUlVFLCBzaW1wbGlmeSA9IEZBTFNFLAogIFJlc3VsdHMsIGZ1bmN0aW9uKHJlc3VsdCkgewogICAgaWYgKGxlbmd0aChyZXN1bHQpID09IDEgJiYgaXMubmEocmVzdWx0KSkgewogICAgICAjIFByb2JsZW0gY2FzZS4KICAgICAgcmV0dXJuKE5BKQogICAgfQogICAgIyBwcmludChwYXN0ZSgiQ2FsY3VsYXRpbmciLCBTeXMudGltZSgpKSkKICAgIAogICAgIyBDYWxjdWxhdGUgdGhlIGRpdmVyc2l0eS4KICAgICMgV2Ugd2lsbCBuZWVkIHRvIGV4dHJhY3QgdGhlIHN5c3RlbSBwcm9wZXJ0aWVzIGZyb20KICAgICMgdGhlIGZpbGUgbmFtZXMgd2hpY2ggd2UgY2FycnkgdGhyb3VnaCB1c2luZyBzYXBwbHkuCiAgICByZXR1cm4oQ2FsY3VsYXRlX0RpdmVyc2l0eShyZXN1bHQpKQogIH0KKQpgYGAKCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQojIEV4cGVjdCB3YXJuaW5ncyBzaW5jZSB3ZSBoYXZlIGFsbCAwIHJvd3Mgb24gb2NjYXNpb24uCkphY2NhcmRTcGFjZSA8LSBzYXBwbHkoCiAgVVNFLk5BTUVTID0gVFJVRSwgc2ltcGxpZnkgPSBGQUxTRSwKICBSZXN1bHRzLCBmdW5jdGlvbihyZXN1bHQpIHsKICAgIGlmIChsZW5ndGgocmVzdWx0KSA9PSAxICYmIGlzLm5hKHJlc3VsdCkpIHsKICAgICAgIyBQcm9ibGVtIGNhc2UuCiAgICAgIHJldHVybihOQSkKICAgIH0KICAgICMgcHJpbnQocGFzdGUoIkNhbGN1bGF0aW5nIiwgU3lzLnRpbWUoKSkpCiAgICAKICAgICMgQ2FsY3VsYXRlIHRoZSBkaXZlcnNpdHkuCiAgICAjIFdlIHdpbGwgbmVlZCB0byBleHRyYWN0IHRoZSBzeXN0ZW0gcHJvcGVydGllcyBmcm9tCiAgICAjIHRoZSBmaWxlIG5hbWVzIHdoaWNoIHdlIGNhcnJ5IHRocm91Z2ggdXNpbmcgc2FwcGx5LgogICAgcmV0dXJuKERpdmVyc2l0eV9qYWNjYXJkX3NwYWNlKHJlc3VsdCkpCiAgfQopCmBgYAoKYGBge3IsIHdhcm5pbmc9RkFMU0V9CiMgRXhwZWN0IHdhcm5pbmdzIHNpbmNlIHdlIGhhdmUgYWxsIDAgcm93cyBvbiBvY2Nhc2lvbi4KSmFjY2FyZFRpbWUgPC0gc2FwcGx5KAogIFVTRS5OQU1FUyA9IFRSVUUsIHNpbXBsaWZ5ID0gRkFMU0UsCiAgUmVzdWx0cywgZnVuY3Rpb24ocmVzdWx0KSB7CiAgICBpZiAobGVuZ3RoKHJlc3VsdCkgPT0gMSAmJiBpcy5uYShyZXN1bHQpKSB7CiAgICAgICMgUHJvYmxlbSBjYXNlLgogICAgICByZXR1cm4oTkEpCiAgICB9CiAgICBwcmludChwYXN0ZSgiQ2FsY3VsYXRpbmciLCBTeXMudGltZSgpKSkKICAgIAogICAgIyBDYWxjdWxhdGUgdGhlIGRpdmVyc2l0eS4KICAgICMgV2Ugd2lsbCBuZWVkIHRvIGV4dHJhY3QgdGhlIHN5c3RlbSBwcm9wZXJ0aWVzIGZyb20KICAgICMgdGhlIGZpbGUgbmFtZXMgd2hpY2ggd2UgY2FycnkgdGhyb3VnaCB1c2luZyBzYXBwbHkuCiAgICByZXR1cm4oRGl2ZXJzaXR5X2phY2NhcmRfdGltZShyZXN1bHQpKQogICAgIyBUb28gbWFueSB0aW1lIHBvaW50cyBmb3IgY2FsY3VsYXRpb25zLgogICAgIyBOZWVkcyB0byBoYXZlIGxvZyhsZW5ndGgodGltZXMpXjIsIGJhc2UgPSAyKSA8IDMxLgogICAgIyA9PiBsZW5ndGgodGltZXMpIDwgNDYzNDAgb3Igc28uCiAgfQopCmBgYAoKYGBge3IsIGV2YWw9VFJVRX0KU3BlY2llc1ByZXNlbmNlIDwtICBzYXBwbHkoCiAgVVNFLk5BTUVTID0gVFJVRSwgc2ltcGxpZnkgPSBGQUxTRSwKICBSZXN1bHRzLCBmdW5jdGlvbihyZXN1bHQpIHsKICAgIGlmIChsZW5ndGgocmVzdWx0KSA9PSAxICYmIGlzLm5hKHJlc3VsdCkpIHsKICAgICAgIyBQcm9ibGVtIGNhc2UuCiAgICAgIHJldHVybihOQSkKICAgIH0KICAgICMgcHJpbnQocGFzdGUoIkNhbGN1bGF0aW5nIiwgU3lzLnRpbWUoKSkpCiAgICAKICAgICMgQ2FsY3VsYXRlIHRoZSBkaXZlcnNpdHkuCiAgICAjIFdlIHdpbGwgbmVlZCB0byBleHRyYWN0IHRoZSBzeXN0ZW0gcHJvcGVydGllcyBmcm9tCiAgICAjIHRoZSBmaWxlIG5hbWVzIHdoaWNoIHdlIGNhcnJ5IHRocm91Z2ggdXNpbmcgc2FwcGx5LgogICAgcmV0dXJuKENhbGN1bGF0ZV9TcGVjaWVzKHJlc3VsdCkpCiAgfQopCmBgYAoKYGBge3J9ClByb3BlcnRpZXMgPC0gc3Ryc3BsaXQobmFtZXMoRGl2ZXJzaXR5KSwgJy0nLCAKICAgICAgICAgICAgICAgICAgICAgICBmaXhlZCA9IFRSVUUpCiMgMXN0IENodW5rOiBOYW1lLCBEaXNjYXJkCiMgMm5kIENodW5rOiBJdGVyYXRpb24gKyBEaXN0YW5jZQojIDNyZCBDaHVuazogUmVzdWx0IG9yIEV4dGluY3Rpb24gUmF0ZSAob3IgQXJyaXZhbD8pCiMgNHRoIENodW5rOiBOdW1iZXIgb2YgRW52aXJvbm1lbnRzCiMgNXRoIENodW5rOiBTcGFjZSBUeXBlICsgLlJEYXRhCiMgTm90ZSB0aGUgbWl4IG9mIEtleXdvcmQgYW5kIExvY2F0aW9uIFN0cnVjdHVyZSAob29wcykuCiMgTm90ZSBhbHNvIHRoYXQgdGhpcyBzdHJzcGxpdCBjaGFyYWN0ZXIgaXMgYSBiYWQgZGVjaXNpb24gYW5kIHNob3VsZCBiZSBjaGFuZ2VkIGZvciBuZXh0IHRpbWUuIChEJ29oLikKIyAoRS5nLiBEYXRlcyBERC1NTS1ZWVlZLCBEZWNpbWFscyAxLjM1ZS0wNS4pClByb3BlcnRpZXMgPC0gZGF0YS5mcmFtZSgKICBkby5jYWxsKHJiaW5kLCBQcm9wZXJ0aWVzKSwKICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UKKQpuYW1lcyhQcm9wZXJ0aWVzKVsxOjVdIDwtIGMoCiAgIk5hbWUiLCAiSXRlckFORERpc3QiLCAiTW9kaWZpZXIiLCAiRW52TnVtIiwgIlNwYWNlQU5ELlJEYXRhIgopCgpQcm9wZXJ0aWVzJEZ1bGxOYW1lIDwtIG5hbWVzKERpdmVyc2l0eSkKCiMgQ2FwdHVyZSB0aGUgcG9zaXRpb24gYmV0d2VlbiB0aGUgdGV4dCAoZmlyc3QgZ3JvdXApCiMgYW5kIHRoZSBzZXQgb2YgbnVtYmVycyAoc29tZWhvdyB3aXRob3V0IHRoZSArKS4KIyBUaGUgXFxLIHJlc2V0cyBzbyB0aGF0IHdlIGRvIG5vdCBjYXB0dXJlIGFueSB0ZXh0LgpwYXR0ZXJuU3RyaW5nIDwtICIoKD8+W2EtekEtWl0rKSg/PVswLTllRV0pKVxcSyIKCiMgU3BsaXQgc3RyaW5ncy4gU29tZSBvZiB0aGUgdHJpY2sgd2lsbCBiZSB0byBpbnRyb2R1Y2UKIyBhIGNoYXJhY3RlciB0byBtYWtlIHRoZSBzZXBhcmF0aW9uIGFyb3VuZC4gV2UgdXNlICJfIi4KUHJvcGVydGllcyA8LSBQcm9wZXJ0aWVzICU+JSBkcGx5cjo6bXV0YXRlKAogIEl0ZXJBTkREaXN0ID0gZ3N1YihwYXR0ZXJuID0gcGF0dGVyblN0cmluZywgCiAgICAgICAgICAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gIl8iLCAKICAgICAgICAgICAgICAgICAgICAgeCA9IEl0ZXJBTkREaXN0LCBwZXJsID0gVFJVRSksCiAgTW9kaWZpZXIgPSBnc3ViKHBhdHRlcm4gPSBwYXR0ZXJuU3RyaW5nLCAKICAgICAgICAgICAgICAgICAgcmVwbGFjZW1lbnQgPSAiXyIsIAogICAgICAgICAgICAgICAgICB4ID0gTW9kaWZpZXIsIHBlcmwgPSBUUlVFKSwKICBFbnZOdW0gPSBnc3ViKHBhdHRlcm4gPSBwYXR0ZXJuU3RyaW5nLCAKICAgICAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gIl8iLCAKICAgICAgICAgICAgICAgIHggPSBFbnZOdW0sIHBlcmwgPSBUUlVFKQopICU+JSB0aWR5cjo6c2VwYXJhdGUoCiAgSXRlckFORERpc3QsIGludG8gPSBjKCJJdGVyIiwgIkRpc3RhbmNlIiksCiAgc2VwID0gIltfXSIsIGZpbGwgPSAicmlnaHQiCikgJT4lIHRpZHlyOjpzZXBhcmF0ZSgKICBNb2RpZmllciwgaW50byA9IGMoIk1vZGlmaWVyIiwgIk1vZEludGVuc2l0eSIpLAogIHNlcCA9ICJbX10iLCBmaWxsID0gInJpZ2h0IgopICU+JSB0aWR5cjo6c2VwYXJhdGUoCiAgRW52TnVtLCBpbnRvID0gYygiRW52IiwgIkVudmlyb25tZW50cyIpLAogIHNlcCA9ICJbX10iCikgJT4lIHRpZHlyOjpzZXBhcmF0ZSgKICBTcGFjZUFORC5SRGF0YSwgaW50byA9IGMoIlNwYWNlIiwgIi5SRGF0YSIpLAogIHNlcCA9ICJbLl0iCikgJT4lIGRwbHlyOjpzZWxlY3QoCiAgLU5hbWUsIC0uUkRhdGEsIC1FbnYKKSAlPiUgZHBseXI6Om11dGF0ZSgKICBEaXN0YW5jZSA9IGRwbHlyOjpjYXNlX3doZW4oCiAgICBpcy5uYShEaXN0YW5jZSkgfiAiMWUrMDAiLAogICAgVFJVRSB+IERpc3RhbmNlCiAgKQopCmBgYAoKYGBge3J9CkRpdmVyc2l0eSA8LSBsYXBwbHkoMTpsZW5ndGgoRGl2ZXJzaXR5KSwKICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbihpLCBkZiwgbm0pIHsKICAgICAgICAgICAgICAgICAgICAgIGRmW1tpXV0gJT4lIG11dGF0ZSgKICAgICAgICAgICAgICAgICAgICAgICAgU2ltdWxhdGlvbiA9IG5tW2ldCiAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgfSwgCiAgICAgICAgICAgICAgICAgICAgZGYgPSBEaXZlcnNpdHksCiAgICAgICAgICAgICAgICAgICAgbm0gPSBuYW1lcyhEaXZlcnNpdHkpKQpgYGAKCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQpKYWNjYXJkU3BhY2UgPC0gbGFwcGx5KDE6bGVuZ3RoKEphY2NhcmRTcGFjZSksCiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oaSwgZGYsIG5tKSB7CiAgICAgICAgICAgICAgICAgICAgICBkZltbaV1dICU+JSBkcGx5cjo6YmluZF9yb3dzKAogICAgICAgICAgICAgICAgICAgICAgICAjIE5lZWQgdG8gYWNjb3VudCBmb3IgdGhlIGJ5IHRpbWVzLi4uCiAgICAgICAgICAgICAgICAgICAgICAgICMgR2VuZXJhdGVzIGF0dHJpYnV0ZSB3YXJuaW5ncy4KICAgICAgICAgICAgICAgICAgICAgICkgJT4lIG11dGF0ZSgKICAgICAgICAgICAgICAgICAgICAgICAgU2ltdWxhdGlvbiA9IG5tW2ldCiAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgfSwgCiAgICAgICAgICAgICAgICAgICAgZGYgPSBKYWNjYXJkU3BhY2UsCiAgICAgICAgICAgICAgICAgICAgbm0gPSBuYW1lcyhKYWNjYXJkU3BhY2UpKQpgYGAKCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQpKYWNjYXJkVGltZSA8LSBsYXBwbHkoMTpsZW5ndGgoSmFjY2FyZFRpbWUpLAogICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKGksIGRmLCBubSkgewogICAgICAgICAgICAgICAgICAgICAgZGZbW2ldXSAlPiUgZHBseXI6OmJpbmRfcm93cygKICAgICAgICAgICAgICAgICAgICAgICAgIyBOZWVkIHRvIGFjY291bnQgZm9yIHRoZSBieSBlbnZzLi4uCiAgICAgICAgICAgICAgICAgICAgICAgICMgR2VuZXJhdGVzIGF0dHJpYnV0ZSB3YXJuaW5ncy4KICAgICAgICAgICAgICAgICAgICAgICkgJT4lIG11dGF0ZSgKICAgICAgICAgICAgICAgICAgICAgICAgU2ltdWxhdGlvbiA9IG5tW2ldCiAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgfSwgCiAgICAgICAgICAgICAgICAgICAgZGYgPSBKYWNjYXJkVGltZSwKICAgICAgICAgICAgICAgICAgICBubSA9IG5hbWVzKEphY2NhcmRUaW1lKSkKYGBgCgpgYGB7ciwgZXZhbD1UUlVFfQpTcGVjaWVzUHJlc2VuY2UgPC0gbGFwcGx5KDE6bGVuZ3RoKFNwZWNpZXNQcmVzZW5jZSksCiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oaSwgZGYsIG5tKSB7CiAgICAgICAgICAgICAgICAgICAgICBkZltbaV1dICU+JSBtdXRhdGUoCiAgICAgICAgICAgICAgICAgICAgICAgIFNpbXVsYXRpb24gPSBubVtpXQogICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgIH0sIAogICAgICAgICAgICAgICAgICAgIGRmID0gU3BlY2llc1ByZXNlbmNlLAogICAgICAgICAgICAgICAgICAgIG5tID0gbmFtZXMoU3BlY2llc1ByZXNlbmNlKSkKYGBgCgpgYGB7cn0KRGl2ZXJzaXR5IDwtIGRwbHlyOjpsZWZ0X2pvaW4oCiAgZHBseXI6OmJpbmRfcm93cyhEaXZlcnNpdHkpLAogIFByb3BlcnRpZXMsCiAgYnkgPSBjKCJTaW11bGF0aW9uIiA9ICJGdWxsTmFtZSIpCikKYGBgCgpgYGB7cn0KSmFjY2FyZFNwYWNlIDwtIGRwbHlyOjpsZWZ0X2pvaW4oCiAgZHBseXI6OmJpbmRfcm93cyhKYWNjYXJkU3BhY2UpLAogIFByb3BlcnRpZXMsCiAgYnkgPSBjKCJTaW11bGF0aW9uIiA9ICJGdWxsTmFtZSIpCikKYGBgCgpgYGB7cn0KSmFjY2FyZFRpbWUgPC0gZHBseXI6OmxlZnRfam9pbigKICBkcGx5cjo6YmluZF9yb3dzKEphY2NhcmRUaW1lKSwKICBQcm9wZXJ0aWVzLAogIGJ5ID0gYygiU2ltdWxhdGlvbiIgPSAiRnVsbE5hbWUiKQopCmBgYAoKYGBge3IsIGV2YWw9VFJVRX0KU3BlY2llc1ByZXNlbmNlIDwtIGRwbHlyOjpsZWZ0X2pvaW4oCiAgZHBseXI6OmJpbmRfcm93cyhTcGVjaWVzUHJlc2VuY2UpLAogIFByb3BlcnRpZXMsCiAgYnkgPSBjKCJTaW11bGF0aW9uIiA9ICJGdWxsTmFtZSIpCikKYGBgCgpgYGB7ciwgZXZhbD1GQUxTRX0KRGl2ZXJzaXR5IDwtIERpdmVyc2l0eSAlPiUgZHBseXI6Om11dGF0ZSgKICBEaXN0YW5jZSA9IGRwbHlyOjpjYXNlX3doZW4oCiAgICBpcy5uYShEaXN0YW5jZSkgfiAiMWUrMDAiLAogICAgVFJVRSB+IERpc3RhbmNlCiAgKQopCmBgYAoKIyMjIEFscGhhIFJpY2huZXNzIHsudGFic2V0fQoKIyMjIyBPdmVyYWxsCmBgYHtyfQpnZ3Bsb3QyOjpnZ3Bsb3QoCiAgRGl2ZXJzaXR5ICU+JSBkcGx5cjo6ZmlsdGVyKAogICAgTWVhc3VyZW1lbnQgPT0gIlJpY2huZXNzIiwKICAgIEVudmlyb25tZW50ICE9ICJHYW1tYSIsCiAgICBTcGFjZSAhPSAiUmluZyIsCiAgICBFbnZpcm9ubWVudCAhPSAiTWVhbiIKICApLCAKICBnZ3Bsb3QyOjphZXMoCiAgICB4ID0gVGltZSwKICAgIHkgPSBWYWx1ZSwKICAgIGNvbG9yID0gZmFjdG9yKEVudmlyb25tZW50KSwKICAgIGFscGhhID0gaWZlbHNlKEVudmlyb25tZW50ICVpbiUgYygiMyIsICI3IiwgIk1lYW4iKSwgMSwgMC4zKQogICkKKSArIGdncGxvdDI6Omdlb21fbGluZSgKKSArIGdncGxvdDI6Omdlb21fbGluZSgKICBkYXRhID0gRGl2ZXJzaXR5ICU+JSBkcGx5cjo6ZmlsdGVyKAogICAgTWVhc3VyZW1lbnQgPT0gIlJpY2huZXNzIiwKICAgIEVudmlyb25tZW50ICE9ICJHYW1tYSIsCiAgICBTcGFjZSAhPSAiUmluZyIsCiAgICBFbnZpcm9ubWVudCA9PSAiTWVhbiIKICApLCAKICBjb2xvciA9ICJibGFjayIKKSArIGdncGxvdDI6Omd1aWRlcygKICBhbHBoYSA9ICJub25lIgopICsgZ2dwbG90Mjo6c2NhbGVfY29sb3JfZGlzY3JldGUoCiAgIkVudmlyb25tZW50IgopICsgZ2dwbG90Mjo6bGFicygKICB5ID0gIlJpY2huZXNzIiwKICB4ID0gcGFzdGUwKCJUaW1lLCAiLCBkaXZpZGVfdGltZV9ieSwgIiB1bml0cyIpLAogIHRpdGxlID0gIk92ZXJ2aWV3IG9mIEFscGhhIFJpY2huZXNzIG92ZXIgVGltZSBieSBTeXN0ZW0gUHJvcGVydGllcyIsCiAgY2FwdGlvbiA9ICJFYWNoIHJvdyBoYXMgdGhlIHNhbWUgYXJyaXZhbCBhbmQgZXh0aW5jdGlvbiBldmVudHMuIgopICsgZ2dwbG90Mjo6ZmFjZXRfZ3JpZCgKICBNb2RpZmllciArIE1vZEludGVuc2l0eSB+IFNwYWNlICsgRGlzdGFuY2UKKQojIGdncGxvdDI6Omdnc2F2ZShvdmVyYWxscmljaCArIGdncGxvdDI6OmNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLCAyNSkpLCBmaWxlbmFtZSA9ICJNTkEtQWxwaGFSaWNobmVzcy1PdmVydmlldy5wZGYiLCBkcGkgPSAicmV0aW5hIiwgd2lkdGggPSAxMSwgaGVpZ2h0ID0gOCkKYGBgCgpgYGB7cn0KUGxvdF9SaWNobmVzcyA8LSBmdW5jdGlvbihkZikgewogIHRlbXBuYW1lIDwtIHBhc3RlKHVuaXF1ZShkZiRTaW11bGF0aW9uKSwgY29sbGFwc2UgPSAiICIpCiAgCiAgdGVtcCA8LSBnZ3Bsb3QyOjpnZ3Bsb3QoCiAgICBkZiAlPiUgZHBseXI6OmZpbHRlcigKICAgICAgTWVhc3VyZW1lbnQgPT0gIlJpY2huZXNzIiwKICAgICAgRW52aXJvbm1lbnQgIT0gIkdhbW1hIiwKICAgICAgRW52aXJvbm1lbnQgIT0gIk1lYW4iCiAgICApLCAKICAgIGdncGxvdDI6OmFlcygKICAgICAgeCA9IFRpbWUsCiAgICAgIHkgPSBWYWx1ZSwKICAgICAgY29sb3IgPSBmYWN0b3IoRW52aXJvbm1lbnQpLAogICAgICBhbHBoYSA9IGlmZWxzZShFbnZpcm9ubWVudCAlaW4lIGMoIjMiLCAiNyIsICJNZWFuIiksIDEsIDAuMykKICAgICkKICApICsgZ2dwbG90Mjo6Z2VvbV9saW5lKAogICkgKyBnZ3Bsb3QyOjpnZW9tX2xpbmUoCiAgICBkYXRhID0gZGYgJT4lIGRwbHlyOjpmaWx0ZXIoCiAgICAgIE1lYXN1cmVtZW50ID09ICJSaWNobmVzcyIsCiAgICAgIEVudmlyb25tZW50ICE9ICJHYW1tYSIsCiAgICAgIEVudmlyb25tZW50ID09ICJNZWFuIgogICAgKSwgCiAgICBjb2xvciA9ICJibGFjayIKICApICsgZ2dwbG90Mjo6Z3VpZGVzKAogICAgYWxwaGEgPSAibm9uZSIKICApICsgZ2dwbG90Mjo6c2NhbGVfY29sb3JfZGlzY3JldGUoCiAgICAiRW52aXJvbm1lbnQiCiAgKSArIGdncGxvdDI6OmxhYnMoCiAgICB0aXRsZSA9IHRlbXBuYW1lLAogICAgeCA9IHBhc3RlMCgiVGltZSwgIiwgZGl2aWRlX3RpbWVfYnksICIgdW5pdHMiKSwKICAgIHkgPSAiUmljaG5lc3MiCiAgKQogIAogIHJldHVybih0ZW1wKQp9CgpQbG90c19SaWNobmVzc19hbHBoYSA8LSBEaXZlcnNpdHkgJT4lIGRwbHlyOjpncm91cF9zcGxpdCgKICBTaW11bGF0aW9uCikgJT4lIHB1cnJyOjptYXAoCiAgUGxvdF9SaWNobmVzcwopCiMgSW4gdGhlIG5leHQgY2h1bmssIHdlIHVzZQojIHd3dy5yLWJsb2dnZXJzLmNvbS8yMDIwLzA3L3Byb2dyYW1tYXRpY2FsbHktY3JlYXRlLW5ldy1nZWFkaW5ncy1hbmQtb3V0cHV0cy1pbi1ybWFya2Rvd24vCgpgYGAKCmBgYHtyLCBlY2hvPUZBTFNFLCByZXN1bHRzID0gImFzaXMifQpmb3IgKGkgaW4gMSA6IGxlbmd0aChQbG90c19SaWNobmVzc19hbHBoYSkpIHsKICBjYXQoIiAgXG5cbiIpCiAgY2F0KCIjIyMjIFNpbTogIiwgaSwgIiAgXG5cbiIpICMgQ3JlYXRlIDR0aCBsZXZlbCBoZWFkaW5ncwogIAogIHByaW50KAogICAgUGxvdHNfUmljaG5lc3NfYWxwaGFbW2ldXQogICkKICAKICBjYXQoIiAgXG5cbiIpCn0KYGBgCgoKIyMjIEV2ZW5uZXNzIHsudGFic2V0fQoKIyMjIyBPdmVyYWxsCmBgYHtyfQpnZ3Bsb3QyOjpnZ3Bsb3QoCiAgRGl2ZXJzaXR5ICU+JSBkcGx5cjo6ZmlsdGVyKAogICAgTWVhc3VyZW1lbnQgPT0gIkV2ZW5uZXNzIiwKICAgIEVudmlyb25tZW50ICE9ICJHYW1tYSIsCiAgICBTcGFjZSAhPSAiUmluZyIsCiAgICBFbnZpcm9ubWVudCAhPSAiTWVhbiIKICApLCAKICBnZ3Bsb3QyOjphZXMoCiAgICB4ID0gVGltZSwKICAgIHkgPSBWYWx1ZSwKICAgIGNvbG9yID0gZmFjdG9yKEVudmlyb25tZW50KSwKICAgIGFscGhhID0gaWZlbHNlKEVudmlyb25tZW50ICVpbiUgYygiMyIsICI3IiwgIk1lYW4iKSwgMSwgMC4zKQogICkKKSArIGdncGxvdDI6Omdlb21fbGluZSgKKSArIGdncGxvdDI6Omdlb21fbGluZSgKICBkYXRhID0gRGl2ZXJzaXR5ICU+JSBkcGx5cjo6ZmlsdGVyKAogICAgTWVhc3VyZW1lbnQgPT0gIkV2ZW5uZXNzIiwKICAgIEVudmlyb25tZW50ICE9ICJHYW1tYSIsCiAgICBTcGFjZSAhPSAiUmluZyIsCiAgICBFbnZpcm9ubWVudCA9PSAiTWVhbiIKICApLCAKICBjb2xvciA9ICJibGFjayIKKSArIGdncGxvdDI6Omd1aWRlcygKICBhbHBoYSA9ICJub25lIgopICsgZ2dwbG90Mjo6c2NhbGVfY29sb3JfZGlzY3JldGUoCiAgIkVudmlyb25tZW50IgopICsgZ2dwbG90Mjo6bGFicygKICB5ID0gIkV2ZW5uZXNzIiwKICB4ID0gcGFzdGUwKCJUaW1lLCAiLCBkaXZpZGVfdGltZV9ieSwgIiB1bml0cyIpLAogIHRpdGxlID0gIk92ZXJ2aWV3IG9mIEV2ZW5uZXNzIG92ZXIgVGltZSBieSBTeXN0ZW0gUHJvcGVydGllcyIsCiAgY2FwdGlvbiA9ICJFYWNoIHJvdyBoYXMgdGhlIHNhbWUgYXJyaXZhbCBhbmQgZXh0aW5jdGlvbiBldmVudHMuIgopICsgZ2dwbG90Mjo6ZmFjZXRfZ3JpZCgKICBNb2RpZmllciArIE1vZEludGVuc2l0eSB+IFNwYWNlICsgRGlzdGFuY2UKKQojIGdncGxvdDI6Omdnc2F2ZShvdmVyYWxscmljaCArIGdncGxvdDI6OmNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLCAyNSkpLCBmaWxlbmFtZSA9ICJNTkEtQWxwaGFSaWNobmVzcy1PdmVydmlldy5wZGYiLCBkcGkgPSAicmV0aW5hIiwgd2lkdGggPSAxMSwgaGVpZ2h0ID0gOCkKYGBgCgpgYGB7cn0KUGxvdF9FdmVubmVzcyA8LSBmdW5jdGlvbihkZikgewogIHRlbXBuYW1lIDwtIHBhc3RlKHVuaXF1ZShkZiRTaW11bGF0aW9uKSwgY29sbGFwc2UgPSAiICIpCiAgCiAgdGVtcCA8LSBnZ3Bsb3QyOjpnZ3Bsb3QoCiAgICBkZiAlPiUgZHBseXI6OmZpbHRlcigKICAgICAgTWVhc3VyZW1lbnQgPT0gIkV2ZW5uZXNzIiwKICAgICAgRW52aXJvbm1lbnQgIT0gIkdhbW1hIiwKICAgICAgRW52aXJvbm1lbnQgIT0gIk1lYW4iCiAgICApLCAKICAgIGdncGxvdDI6OmFlcygKICAgICAgeCA9IFRpbWUsCiAgICAgIHkgPSBWYWx1ZSwKICAgICAgY29sb3IgPSBmYWN0b3IoRW52aXJvbm1lbnQpLAogICAgICBhbHBoYSA9IGlmZWxzZShFbnZpcm9ubWVudCAlaW4lIGMoIjMiLCAiNyIsICJNZWFuIiksIDEsIDAuMykKICAgICkKICApICsgZ2dwbG90Mjo6Z2VvbV9saW5lKAogICkgKyBnZ3Bsb3QyOjpnZW9tX2xpbmUoCiAgICBkYXRhID0gZGYgJT4lIGRwbHlyOjpmaWx0ZXIoCiAgICAgIE1lYXN1cmVtZW50ID09ICJFdmVubmVzcyIsCiAgICAgIEVudmlyb25tZW50ICE9ICJHYW1tYSIsCiAgICAgIEVudmlyb25tZW50ID09ICJNZWFuIgogICAgKSwgCiAgICBjb2xvciA9ICJibGFjayIKICApICsgZ2dwbG90Mjo6Z3VpZGVzKAogICAgYWxwaGEgPSAibm9uZSIKICApICsgZ2dwbG90Mjo6c2NhbGVfY29sb3JfZGlzY3JldGUoCiAgICAiRW52aXJvbm1lbnQiCiAgKSArIGdncGxvdDI6OmxhYnMoCiAgICB0aXRsZSA9IHRlbXBuYW1lLAogICAgeCA9IHBhc3RlMCgiVGltZSwgIiwgZGl2aWRlX3RpbWVfYnksICIgdW5pdHMiKSwKICAgIHkgPSAiRXZlbm5lc3MiCiAgKQogIAogIHJldHVybih0ZW1wKQp9CgpQbG90c19FdmVubmVzcyA8LSBEaXZlcnNpdHkgJT4lIGRwbHlyOjpncm91cF9zcGxpdCgKICBTaW11bGF0aW9uCikgJT4lIHB1cnJyOjptYXAoCiAgUGxvdF9FdmVubmVzcwopCiMgSW4gdGhlIG5leHQgY2h1bmssIHdlIHVzZQojIHd3dy5yLWJsb2dnZXJzLmNvbS8yMDIwLzA3L3Byb2dyYW1tYXRpY2FsbHktY3JlYXRlLW5ldy1oZWFkaW5ncy1hbmQtb3V0cHV0cy1pbi1ybWFya2Rvd24vCgpgYGAKCmBgYHtyLCBlY2hvPUZBTFNFLCByZXN1bHRzID0gImFzaXMifQpmb3IgKGkgaW4gMSA6IGxlbmd0aChQbG90c19FdmVubmVzcykpIHsKICBjYXQoIiAgXG5cbiIpCiAgY2F0KCIjIyMjIFNpbTogIiwgaSwgIiAgXG5cbiIpICMgQ3JlYXRlIDR0aCBsZXZlbCBoZWFkaW5ncwogIAogIHByaW50KAogICAgUGxvdHNfRXZlbm5lc3NbW2ldXQogICkKICAKICBjYXQoIiAgXG5cbiIpCn0KYGBgCgojIyMgR2FtbWEgUmljaG5lc3Mgey50YWJzZXR9CgojIyMjIFJpY2huZXNzCmBgYHtyfQpnZ3Bsb3QyOjpnZ3Bsb3QoCiAgRGl2ZXJzaXR5ICU+JSBkcGx5cjo6ZmlsdGVyKAogICAgTWVhc3VyZW1lbnQgPT0gIlJpY2huZXNzIiwKICAgIEVudmlyb25tZW50ID09ICJHYW1tYSIsCiAgICBTcGFjZSAhPSAiUmluZyIKICApLCAKICBnZ3Bsb3QyOjphZXMoCiAgICB4ID0gVGltZSwKICAgIHkgPSBWYWx1ZQogICkKKSArIGdncGxvdDI6Omdlb21fbGluZSgKKSArIGdncGxvdDI6OmxhYnMoCiAgeSA9ICJSaWNobmVzcyIsCiAgeCA9IHBhc3RlMCgiVGltZSwgIiwgZGl2aWRlX3RpbWVfYnksICIgdW5pdHMiKSwKICB0aXRsZSA9ICJHYW1tYSBSaWNobmVzcyBvdmVyIFRpbWUgYnkgU3lzdGVtIFByb3BlcnRpZXMiLAogIGNhcHRpb24gPSAiRWFjaCByb3cgaGFzIHRoZSBzYW1lIGFycml2YWwgYW5kIGV4dGluY3Rpb24gZXZlbnRzLiIKKSArIGdncGxvdDI6OmZhY2V0X2dyaWQoCiAgTW9kaWZpZXIgKyBNb2RJbnRlbnNpdHkgfiBTcGFjZSArIERpc3RhbmNlCikgKyBnZ3Bsb3QyOjpjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCwgNDUpKQoKIyBnZ3Bsb3QyOjpnZ3NhdmUob3ZlcmFsbGdhbW1hLCBmaWxlbmFtZSA9ICJNTkEtR2FtbWFSaWNobmVzcy1PdmVydmlldy5wZGYiLCBkcGkgPSAicmV0aW5hIiwgd2lkdGggPSAxMSwgaGVpZ2h0ID0gOCkKYGBgCgojIyMgQmV0YSBSaWNobmVzcyB7LnRhYnNldH0KCiMjIyMgJFxnYW1tYSAtIFxhbHBoYSQKYGBge3J9CmdncGxvdDI6OmdncGxvdCgKICBEaXZlcnNpdHkgJT4lIGRwbHlyOjpmaWx0ZXIoCiAgICBNZWFzdXJlbWVudCA9PSAiQmV0YVNwZWNpZXNNaXNzaW5nIiwKICAgIEVudmlyb25tZW50ICE9ICJHYW1tYSIsCiAgICBTcGFjZSAhPSAiUmluZyIsCiAgICBFbnZpcm9ubWVudCAhPSAiTWVhbiIKICApLCAKICBnZ3Bsb3QyOjphZXMoCiAgICB4ID0gVGltZSwKICAgIHkgPSBWYWx1ZSwKICAgIGNvbG9yID0gZmFjdG9yKEVudmlyb25tZW50KSwKICAgIGFscGhhID0gaWZlbHNlKEVudmlyb25tZW50ICVpbiUgYygiMyIsICI3IiwgIk1lYW4iKSwgMSwgMC4zKQogICkKKSArIGdncGxvdDI6Omdlb21fbGluZSgKKSArIGdncGxvdDI6Omdlb21fbGluZSgKICAgIGRhdGEgPSBEaXZlcnNpdHkgJT4lIGRwbHlyOjpmaWx0ZXIoCiAgICAgICAgTWVhc3VyZW1lbnQgPT0gIkJldGFTcGVjaWVzTWlzc2luZyIsCiAgICAgICAgRW52aXJvbm1lbnQgIT0gIkdhbW1hIiwKICAgICAgICBTcGFjZSAhPSAiUmluZyIsCiAgICAgICAgRW52aXJvbm1lbnQgIT0gIk1lYW4iCiAgICApICU+JSBkcGx5cjo6Z3JvdXBfYnkoCiAgICAgICAgTW9kaWZpZXIsIE1vZEludGVuc2l0eSwgU3BhY2UsIERpc3RhbmNlLCBUaW1lCiAgICApICU+JSBkcGx5cjo6c3VtbWFyaXNlKAogICAgICAgIEVudmlyb25tZW50ID0gIk1lYW4iLAogICAgICAgIFZhbHVlID0gbWVhbihWYWx1ZSwgbmEucm0gPSBUUlVFKQogICAgKSwgY29sb3IgPSAiYmxhY2siCikgKyBnZ3Bsb3QyOjpndWlkZXMoCiAgYWxwaGEgPSAibm9uZSIKKSArIGdncGxvdDI6OnNjYWxlX2NvbG9yX2Rpc2NyZXRlKAogICJFbnZpcm9ubWVudCIKKSArIGdncGxvdDI6OmxhYnMoCiAgeSA9ICJBYnNvbHV0ZSBTcGVjaWVzIFR1cm5vdmVyIiwgIyBlbi53aWtpcGVkaWEub3JnL3dpa2kvQmV0YV9kaXZlcnNpdHkKICB4ID0gcGFzdGUwKCJUaW1lLCAiLCBkaXZpZGVfdGltZV9ieSwgIiB1bml0cyIpLAogIHRpdGxlID0gIk92ZXJ2aWV3IG9mIEdhbW1hIC0gQWxwaGEgUmljaG5lc3Mgb3ZlciBUaW1lIGJ5IFN5c3RlbSBQcm9wZXJ0aWVzIiwKICBjYXB0aW9uID0gIkVhY2ggcm93IGhhcyB0aGUgc2FtZSBhcnJpdmFsIGFuZCBleHRpbmN0aW9uIGV2ZW50cy4iCikgKyBnZ3Bsb3QyOjpmYWNldF9ncmlkKAogIE1vZGlmaWVyICsgTW9kSW50ZW5zaXR5IH4gU3BhY2UgKyBEaXN0YW5jZQopCiMgZ2dwbG90Mjo6Z2dzYXZlKG92ZXJhbGxiZXRhbWlzcywgZmlsZW5hbWUgPSAiTU5BLUJldGFNaXNzaW5nLU92ZXJ2aWV3LnBkZiIsIGRwaSA9ICJyZXRpbmEiLCB3aWR0aCA9IDExLCBoZWlnaHQgPSA4KQpgYGAKCiMjIyMgJFxhbHBoYSAvIFxnYW1tYSQKYGBge3J9CmdncGxvdDI6OmdncGxvdCgKICAgIERpdmVyc2l0eSAlPiUgZHBseXI6OmZpbHRlcigKICAgICAgICBNZWFzdXJlbWVudCA9PSAiQmV0YVNwZWNpZXNQZXJjZW50YWdlIiwKICAgICAgICBFbnZpcm9ubWVudCAhPSAiR2FtbWEiLAogICAgICAgIFNwYWNlICE9ICJSaW5nIiwKICAgICAgICBFbnZpcm9ubWVudCAhPSAiTWVhbiIKICAgICksIAogICAgZ2dwbG90Mjo6YWVzKAogICAgICAgIHggPSBUaW1lLAogICAgICAgIHkgPSBWYWx1ZSwKICAgICAgICBjb2xvciA9IGZhY3RvcihFbnZpcm9ubWVudCksCiAgICAgICAgYWxwaGEgPSBpZmVsc2UoRW52aXJvbm1lbnQgJWluJSBjKCIzIiwgIjciLCAiTWVhbiIpLCAxLCAwLjMpCiAgICApCikgKyBnZ3Bsb3QyOjpnZW9tX2xpbmUoCikgKyBnZ3Bsb3QyOjpnZW9tX2xpbmUoCiAgICBkYXRhID0gRGl2ZXJzaXR5ICU+JSBkcGx5cjo6ZmlsdGVyKAogICAgICAgIE1lYXN1cmVtZW50ID09ICJCZXRhU3BlY2llc1BlcmNlbnRhZ2UiLAogICAgICAgIEVudmlyb25tZW50ICE9ICJHYW1tYSIsCiAgICAgICAgU3BhY2UgIT0gIlJpbmciLAogICAgICAgIEVudmlyb25tZW50ICE9ICJNZWFuIgogICAgKSAlPiUgZHBseXI6Omdyb3VwX2J5KAogICAgICAgIE1vZGlmaWVyLCBNb2RJbnRlbnNpdHksIFNwYWNlLCBEaXN0YW5jZSwgVGltZQogICAgKSAlPiUgZHBseXI6OnN1bW1hcmlzZSgKICAgICAgICBFbnZpcm9ubWVudCA9ICJNZWFuIiwKICAgICAgICBWYWx1ZSA9IG1lYW4oVmFsdWUsIG5hLnJtID0gVFJVRSkKICAgICksIGNvbG9yID0gImJsYWNrIgopICsgZ2dwbG90Mjo6Z3VpZGVzKAogICAgYWxwaGEgPSAibm9uZSIKKSArIGdncGxvdDI6OnNjYWxlX2NvbG9yX2Rpc2NyZXRlKAogICAgIkVudmlyb25tZW50IgopICsgZ2dwbG90Mjo6bGFicygKICAgIHkgPSAiUGVyY2VudGFnZSBTcGVjaWVzIFByZXNlbnQiLCAjIGVuLndpa2lwZWRpYS5vcmcvd2lraS9CZXRhX2RpdmVyc2l0eQogICAgeCA9IHBhc3RlMCgiVGltZSwgIiwgZGl2aWRlX3RpbWVfYnksICIgdW5pdHMiKSwKICAgIHRpdGxlID0gIk92ZXJ2aWV3IG9mIEFscGhhL0dhbW1hIFJpY2huZXNzIG92ZXIgVGltZSBieSBTeXN0ZW0gUHJvcGVydGllcyIsCiAgICBjYXB0aW9uID0gIkVhY2ggcm93IGhhcyB0aGUgc2FtZSBhcnJpdmFsIGFuZCBleHRpbmN0aW9uIGV2ZW50cy4iCikgKyBnZ3Bsb3QyOjpmYWNldF9ncmlkKAogICAgTW9kaWZpZXIgKyBNb2RJbnRlbnNpdHkgfiBTcGFjZSArIERpc3RhbmNlCikKIyBnZ3Bsb3QyOjpnZ3NhdmUob3ZlcmFsbGJldGFwZXJjZW50LCBmaWxlbmFtZSA9ICJNTkEtQmV0YVBlcmNlbnQtT3ZlcnZpZXcucGRmIiwgZHBpID0gInJldGluYSIsIHdpZHRoID0gMTEsIGhlaWdodCA9IDgpCmBgYAoKIyMjIyBBbHBoYSB2cyBHYW1tYQoKPCEtLSAKZ2dwbG90Mjo6Z2dwbG90KHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIoTW9kaWZpZXIgPT0gIlJlc3VsdCIsIFNwYWNlID09ICJOb25lIiwgRW52aXJvbm1lbnQgIT0gIk1lYW4iKSwgZ2dwbG90Mjo6YWVzKCB4ID0gR2FtbWEsIHkgPSBWYWx1ZSkpICsgZ2dwbG90Mjo6Z2VvbV9iaW4yZCgpICsgZ2dwbG90Mjo6c2NhbGVfZmlsbF92aXJpZGlzX2MoKQotLT4KCmBgYHtyfQpEaXZlcnNpdHlfQUcgPC0gZHBseXI6OmxlZnRfam9pbigKICBEaXZlcnNpdHkgJT4lIGRwbHlyOjpmaWx0ZXIoCiAgICBNZWFzdXJlbWVudCA9PSAiUmljaG5lc3MiLAogICAgU3BhY2UgIT0gIlJpbmciLAogICAgRW52aXJvbm1lbnQgIT0gIkdhbW1hIgogICksIAogIERpdmVyc2l0eSAlPiUgZHBseXI6OmZpbHRlcigKICAgIE1lYXN1cmVtZW50ID09ICJSaWNobmVzcyIsCiAgICBTcGFjZSAhPSAiUmluZyIsCiAgICBFbnZpcm9ubWVudCA9PSAiR2FtbWEiCiAgKSAlPiUgZHBseXI6OnJlbmFtZSgKICAgIEdhbW1hID0gVmFsdWUKICApICU+JSBkcGx5cjo6c2VsZWN0KAogICAgLUVudmlyb25tZW50CiAgKQopICU+JSBkcGx5cjo6bXV0YXRlKAogIERpc3RhbmNlID0gaWZlbHNlKGlzLm5hKERpc3RhbmNlKSwgMSwgRGlzdGFuY2UpCikKCkRpdmVyc2l0eV9BR19CaW5uZWQgPC0gRGl2ZXJzaXR5X0FHICU+JSBkcGx5cjo6bXV0YXRlKAogICAgVGltZUZsb29yID0gZmxvb3IoVGltZSAqIDEwKSAvIDEwCikgJT4lIGRwbHlyOjpkaXN0aW5jdCgKICAgIE1vZGlmaWVyLCBNb2RJbnRlbnNpdHksIFNwYWNlLCBEaXN0YW5jZSwgIyBTaW11bGF0aW9uL0ZhY2V0cwogICAgRW52aXJvbm1lbnQsIFRpbWVGbG9vciwgIyBHcm91cGluZyBCaW5zCiAgICBWYWx1ZSwgR2FtbWEgIyBWYWx1ZXMuIElmIGVpdGhlciBtb3ZlcywgdGhlIHRyYWplY3RvcnkgZW50ZXJlZCBhIG5ldyBzcXVhcmUuCikKCiMgZ2dwbG90Mjo6Z2dwbG90KAojICAgdGVtcCAlPiUgZHBseXI6OmZpbHRlcigKIyAgICAgTW9kaWZpZXIgPT0gIlJlc3VsdCIsCiMgICAgIFNwYWNlID09ICJOb25lIiwKIyAgICAgRW52aXJvbm1lbnQgIT0gIk1lYW4iCiMgICApLCBnZ3Bsb3QyOjphZXMoCiMgICAgIHggPSBHYW1tYSwKIyAgICAgeSA9IFZhbHVlCiMgICApCiMgKSArIGdncGxvdDI6Omdlb21fYmluMmQoCiMgKSArIGdncGxvdDI6OnNjYWxlX2ZpbGxfdmlyaWRpc19jKAojICkgKyBnZ3Bsb3QyOjpsYWJzKAojICAgVGl0bGUgPSAiTm8gU3BhdGlhbCBTdHJ1Y3R1cmUsIEVxdWFsIEV4dGluY3Rpb24gJiBBcnJpdmFsIFJhdGVzIiwKIyAgIHggPSAiR2FtbWEgUmljaG5lc3MiLAojICAgeSA9ICJBbHBoYSBSaWNobmVzcyIKIyApCmBgYAoKYGBge3J9CmdncGxvdDI6OmdncGxvdCgKICAgIERpdmVyc2l0eV9BRyAlPiUgZHBseXI6OmZpbHRlcigKICAgICAgICBFbnZpcm9ubWVudCAhPSAiTWVhbiIsCiAgICAgICAgU3BhY2UgIT0gIlJpbmciCiAgICApLCBnZ3Bsb3QyOjphZXMoCiAgICAgICAgeCA9IFZhbHVlLAogICAgICAgIHkgPSBHYW1tYQogICAgKQopICsgZ2dwbG90Mjo6Z2VvbV9iaW4yZCgKKSArIGdncGxvdDI6OnNjYWxlX2ZpbGxfdmlyaWRpc19jKAogICAgdHJhbnMgPSAibG9nMTAiCikgKyBnZ3Bsb3QyOjpnZW9tX3BvaW50KAogICAgZGF0YSA9IERpdmVyc2l0eV9BRyAlPiUgZHBseXI6OmZpbHRlcigKICAgICAgICBFbnZpcm9ubWVudCAhPSAiTWVhbiIsCiAgICAgICAgU3BhY2UgIT0gIlJpbmciCiAgICApICU+JSBkcGx5cjo6Z3JvdXBfYnkoCiAgICAgICAgTW9kaWZpZXIsIE1vZEludGVuc2l0eSwgU3BhY2UsIERpc3RhbmNlCiAgICApICU+JSBkcGx5cjo6c3VtbWFyaXNlKAogICAgICAgIEdhbW1hID0gbWVhbihHYW1tYSwgbmEucm0gPSBUUlVFKSwKICAgICAgICBWYWx1ZSA9IG1lYW4oVmFsdWUsIG5hLnJtID0gVFJVRSkKICAgICksIGNvbG9yID0gInJlZCIsIHNpemUgPSAyLCBzaGFwZSA9IDQKKSArIGdncGxvdDI6OmxhYnMoCiAgICB4ID0gIkFscGhhIFJpY2huZXNzIiwKICAgIHkgPSAiR2FtbWEgUmljaG5lc3MiCikgKyBnZ3Bsb3QyOjpmYWNldF9ncmlkKAogICAgTW9kaWZpZXIgKyBNb2RJbnRlbnNpdHkgfiBTcGFjZSArIERpc3RhbmNlCikgKyBnZ3Bsb3QyOjpnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDApCiMgZ2dwbG90Mjo6Z2dzYXZlKG92ZXJhbGxhbHBoYWdhbW1hLCBmaWxlbmFtZSA9ICJNTkEtQWxwaGFHYW1tYS1PdmVydmlldy5wZGYiLCBkcGkgPSAicmV0aW5hIiwgd2lkdGggPSAxMSwgaGVpZ2h0ID0gOCkKYGBgCgpgYGB7cn0KZ2dwbG90Mjo6Z2dwbG90KAogICAgRGl2ZXJzaXR5X0FHX0Jpbm5lZCAlPiUgZHBseXI6OmZpbHRlcigKICAgICAgICBFbnZpcm9ubWVudCAhPSAiTWVhbiIsCiAgICAgICAgU3BhY2UgIT0gIlJpbmciCiAgICApLCBnZ3Bsb3QyOjphZXMoCiAgICAgICAgeCA9IFZhbHVlLAogICAgICAgIHkgPSBHYW1tYQogICAgKQopICsgZ2dwbG90Mjo6Z2VvbV9iaW4yZCgKKSArIGdncGxvdDI6OnNjYWxlX2ZpbGxfdmlyaWRpc19jKAogICAgdHJhbnMgPSAibG9nMTAiCikgKyBnZ3Bsb3QyOjpnZW9tX3BvaW50KAogICAgZGF0YSA9IERpdmVyc2l0eV9BR19CaW5uZWQgJT4lIGRwbHlyOjpmaWx0ZXIoCiAgICAgICAgRW52aXJvbm1lbnQgIT0gIk1lYW4iLAogICAgICAgIFNwYWNlICE9ICJSaW5nIgogICAgKSAlPiUgZHBseXI6Omdyb3VwX2J5KAogICAgICAgIE1vZGlmaWVyLCBNb2RJbnRlbnNpdHksIFNwYWNlLCBEaXN0YW5jZQogICAgKSAlPiUgZHBseXI6OnN1bW1hcmlzZSgKICAgICAgICBHYW1tYSA9IG1lYW4oR2FtbWEsIG5hLnJtID0gVFJVRSksCiAgICAgICAgVmFsdWUgPSBtZWFuKFZhbHVlLCBuYS5ybSA9IFRSVUUpCiAgICApLCBjb2xvciA9ICJyZWQiLCBzaXplID0gMiwgc2hhcGUgPSA0CikgKyBnZ3Bsb3QyOjpsYWJzKAogICAgeCA9ICJBbHBoYSBSaWNobmVzcyIsCiAgICB5ID0gIkdhbW1hIFJpY2huZXNzIiwKICAgIHN1YnRpdGxlID0gIlRyYWplY3RvcmllcyBiaW5uZWQgYnkgdGltZSB0byBlcXVhbGlzZSB0aW1lIHN0ZXBzLiIKKSArIGdncGxvdDI6OmZhY2V0X2dyaWQoCiAgICBNb2RpZmllciArIE1vZEludGVuc2l0eSB+IFNwYWNlICsgRGlzdGFuY2UKKSArIGdncGxvdDI6Omdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCkKIyBnZ3Bsb3QyOjpnZ3NhdmUob3ZlcmFsbGFscGhhZ2FtbWFiaW4sIGZpbGVuYW1lID0gIk1OQS1BbHBoYUdhbW1hQmlubmVkLU92ZXJ2aWV3LnBkZiIsIGRwaSA9ICJyZXRpbmEiLCB3aWR0aCA9IDExLCBoZWlnaHQgPSA4KQpgYGAKCmBgYHtyfQpnZ3Bsb3QyOjpnZ3Bsb3QoIAogICAgRGl2ZXJzaXR5X0FHX0Jpbm5lZCAlPiUgZHBseXI6OmZpbHRlcigKICAgICAgICBFbnZpcm9ubWVudCAhPSAiTWVhbiIsCiAgICAgICAgU3BhY2UgIT0gIlJpbmciCiAgICApICU+JSBkcGx5cjo6Z3JvdXBfYnkoCiAgICAgICAgTW9kaWZpZXIsIE1vZEludGVuc2l0eSwgU3BhY2UsIERpc3RhbmNlCiAgICApICU+JSBkcGx5cjo6c3VtbWFyaXNlKAogICAgICAgIEdhbW1hID0gbWVhbihHYW1tYSwgbmEucm0gPSBUUlVFKSwKICAgICAgICBWYWx1ZSA9IG1lYW4oVmFsdWUsIG5hLnJtID0gVFJVRSkKICAgICksIAogICAgZ2dwbG90Mjo6YWVzKAogICAgICAgIHggPSBWYWx1ZSwKICAgICAgICB5ID0gR2FtbWEsCiAgICAgICAgY29sb3IgPSBpbnRlcmFjdGlvbihNb2RpZmllciwgTW9kSW50ZW5zaXR5KSwKICAgICAgICBzaGFwZSA9IGludGVyYWN0aW9uKFNwYWNlLCBEaXN0YW5jZSkKICAgICkKKSArIGdncGxvdDI6Omdlb21fcG9pbnQoCiAgICBzaXplID0gMgopICsgZ2dwbG90Mjo6bGFicygKICAgIHggPSAiQWxwaGEgUmljaG5lc3MiLAogICAgeSA9ICJHYW1tYSBSaWNobmVzcyIsCiAgICBzdWJ0aXRsZSA9ICJUcmFqZWN0b3JpZXMgYmlubmVkIGJ5IHRpbWUgdG8gZXF1YWxpc2UgdGltZSBzdGVwcy4iCikgKyBnZ3Bsb3QyOjpnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDApCiMgZ2dwbG90Mjo6Z2dzYXZlKG92ZXJhbGxhbHBoYWdhbW1hbWVhbiwgZmlsZW5hbWUgPSAiTU5BLUFscGhhR2FtbWFCaW5uZWQtTWVhbnMucGRmIiwgZHBpID0gInJldGluYSIsIHdpZHRoID0gMTEsIGhlaWdodCA9IDgpCmBgYAoKIyMjIyBKYWNjYXJkLCBTcGFjZQoKYGBge3J9CmdncGxvdDI6OmdncGxvdCgKICBKYWNjYXJkU3BhY2UgJT4lIGRwbHlyOjpmaWx0ZXIoVGltZSA+IDMsIFNwYWNlICE9ICJSaW5nIiksCiAgZ2dwbG90Mjo6YWVzKHggPSBUaW1lLCB5ID0gSmFjY2FyZCwgCiAgICAgICAgICAgICAgIGNvbG9yID0gaW50ZXJhY3Rpb24oRW52MSwgRW52MikKICApCikgKyBnZ3Bsb3QyOjpnZW9tX2xpbmUoCiAgYWxwaGEgPSAwLjMKKSArIGdncGxvdDI6Omdlb21fbGluZSgKICBkYXRhID0gSmFjY2FyZFNwYWNlICU+JSBkcGx5cjo6ZmlsdGVyKFRpbWUgPiAzLCBTcGFjZSAhPSAiUmluZyIpICU+JSBkcGx5cjo6Z3JvdXBfYnkoCiAgICBUaW1lLCBEaXN0YW5jZSwgTW9kaWZpZXIsIE1vZEludGVuc2l0eSwgU3BhY2UKICApICU+JSBkcGx5cjo6c3VtbWFyaXNlKAogICAgSmFjY2FyZCA9IG1lYW4oSmFjY2FyZCwgbmEucm0gPSBUUlVFKQogICksCiAgZ2dwbG90Mjo6YWVzKAogICAgeCA9IFRpbWUsIHkgPSBKYWNjYXJkCiAgKSwKICBpbmhlcml0LmFlcyA9IEZBTFNFLCBjb2xvciA9ICJibGFjayIKKSArIGdncGxvdDI6OmZhY2V0X2dyaWQoCiAgICBNb2RpZmllciArIE1vZEludGVuc2l0eSB+IFNwYWNlICsgRGlzdGFuY2UKKSArIGdncGxvdDI6Omd1aWRlcygKICBjb2xvciA9ICJub25lIgopCmBgYAoKIyMjIyBKYWNjYXJkLCBUaW1lCjwhLS0gSSB0aGluayBJIHNob3VsZCBiZSBhYmxlIHRvIGRvIHRoZSAyZGJpbiwgYnV0IHdpdGggYSBub3JtYWxpc2F0aW9uLiBTaG91bGQgYmUgYSBuaWNlIGV4cGVyaW1lbnQgYW5kIGVhc3kgcmVzdWx0IHdoZW4gSSBhbSBtb3JlIGF3YWtlLiAtLT4KPCEtLSBQcm9iYWJseSB3b24ndCB3b3JrIGFzIHdlbGwgYXMgSSBoYWQgaW1hZ2luZWQgdW5mb3J0dW5hdGVseS4gV2UnbGwgdHJ5IHRoZSBmb2xsb3dpbmcuIC0tPgoKYGBge3J9CmdncGxvdDI6OmdncGxvdCgKICBKYWNjYXJkVGltZSAlPiUgZHBseXI6OmZpbHRlcigKICAgIFNwYWNlICE9ICJSaW5nIgogICkgJT4lIGRwbHlyOjpncm91cF9ieSgKICAgIEVudmlyb25tZW50LCBEaXN0YW5jZSwgU3BhY2UsIE1vZGlmaWVyLCBNb2RJbnRlbnNpdHkKICApICU+JSBkcGx5cjo6bXV0YXRlKAogICAgVGltZURpZmZlcmVuY2UgPSBUaW1lMiAtIFRpbWUxCiAgKSwKICBnZ3Bsb3QyOjphZXMoCiAgICB4ID0gVGltZURpZmZlcmVuY2UsCiAgICB5ID0gSmFjY2FyZAogICkKKSArIGdncGxvdDI6Omdlb21fYmluMmQoCikgKyBnZ3Bsb3QyOjpmYWNldF9ncmlkKAogICAgTW9kaWZpZXIgKyBNb2RJbnRlbnNpdHkgfiBTcGFjZSArIERpc3RhbmNlCikgKyBnZ3Bsb3QyOjpzY2FsZV9maWxsX3ZpcmlkaXNfYygKICB0cmFucyA9ICJsb2ciCikKYGBgCgpgYGB7cn0KZ2dwbG90Mjo6Z2dwbG90KAogIEphY2NhcmRUaW1lICU+JSBkcGx5cjo6ZmlsdGVyKAogICAgU3BhY2UgIT0gIlJpbmciLAogICAgU3BhY2UgPT0gIk5vbmUiLAogICAgTW9kaWZpZXIgPT0gIlJlc3VsdCIKICApICU+JSBkcGx5cjo6Z3JvdXBfYnkoCiAgICBFbnZpcm9ubWVudCwgRGlzdGFuY2UsIFNwYWNlLCBNb2RpZmllciwgTW9kSW50ZW5zaXR5CiAgKSAlPiUgZHBseXI6Om11dGF0ZSgKICAgIFRpbWVEaWZmZXJlbmNlID0gVGltZTIgLSBUaW1lMQogICksCiAgZ2dwbG90Mjo6YWVzKAogICAgeCA9IFRpbWVEaWZmZXJlbmNlLAogICAgeSA9IEphY2NhcmQKICApCikgKyBnZ3Bsb3QyOjpnZW9tX2JpbjJkKAopICsgZ2dwbG90Mjo6ZmFjZXRfd3JhcCgKICAgIH4gRW52aXJvbm1lbnQKKSArIGdncGxvdDI6OnNjYWxlX2ZpbGxfdmlyaWRpc19jKAogIHRyYW5zID0gImxvZyIKKQpgYGAKCiMjIyBTcGVjaWVzIFByZXNlbmNlCgpgYGB7cn0KIyBnZ3Bsb3QyOjpnZ3Bsb3QoCiMgICBTcGVjaWVzUHJlc2VuY2UgJT4lIGRwbHlyOjpmaWx0ZXIoCiMgICAgIFNwYWNlICE9ICJSaW5nIiwKIyAgICAgVGltZUZsb29yID4gMC4yICMgUmVtb3ZlICJidXJuLWluIiB3aGljaCBoYXMgImltcG9zc2libHkiIGhpZ2ggcHJlc2VuY2UuIAojICAgKSwKIyAgIGdncGxvdDI6OmFlcygKIyAgICAgeCA9IFRpbWVGbG9vciwKIyAgICAgeSA9IFNwZWNpZXMKIyAgICkKIyApICsgZ2dwbG90Mjo6Z2VvbV9iaW4yZCgKIyAgIGJpbndpZHRoID0gYygwLjEsIDEpCiMgKSArIGdncGxvdDI6OnNjYWxlX2ZpbGxfdmlyaWRpc19jKAojICkrIGdncGxvdDI6OmZhY2V0X2dyaWQoCiMgICBNb2RpZmllciArIE1vZEludGVuc2l0eSB+IFNwYWNlICsgRGlzdGFuY2UKIyApCmdncGxvdDI6OmdncGxvdCgKICBTcGVjaWVzUHJlc2VuY2UgJT4lIGRwbHlyOjpmaWx0ZXIoCiAgICBTcGFjZSAhPSAiUmluZyIKICApICU+JSBkcGx5cjo6Z3JvdXBfYnkoCiAgICBNb2RpZmllciwgTW9kSW50ZW5zaXR5LCBTcGFjZSwgRGlzdGFuY2UsCiAgICBTcGVjaWVzLCBUaW1lCiAgKSAlPiUgZHBseXI6OnN1bW1hcmlzZSgKICAgIENvdW50ID0gbigpCiAgKSwKICBnZ3Bsb3QyOjphZXMoeCA9IFRpbWUsIHkgPSBTcGVjaWVzLCBjb2xvciA9IENvdW50KQopICsgZ2dwbG90Mjo6Z2VvbV9wb2ludCgKICBzaGFwZSA9ICcuJwopICsgZ2dwbG90Mjo6c2NhbGVfY29sb3JfdmlyaWRpc19jKAopICsgZ2dwbG90Mjo6ZmFjZXRfZ3JpZCgKICBNb2RpZmllciArIE1vZEludGVuc2l0eSB+IFNwYWNlICsgRGlzdGFuY2UKKSArIGdncGxvdDI6Omdlb21faGxpbmUoCiAgeWludGVyY2VwdCA9IDM0LjUsIGNvbG9yID0gInJlZCIKKQpgYGAKCmBgYHtyfQpnZ3Bsb3QyOjpnZ3Bsb3QoCiAgU3BlY2llc1ByZXNlbmNlICU+JSBkcGx5cjo6ZmlsdGVyKAogICAgU3BhY2UgIT0gIlJpbmciCiAgKSAlPiUgZHBseXI6Omdyb3VwX2J5KAogICAgTW9kaWZpZXIsIE1vZEludGVuc2l0eSwgU3BhY2UsIERpc3RhbmNlLAogICAgU3BlY2llcywgVGltZQogICkgJT4lIGRwbHlyOjpzdW1tYXJpc2UoCiAgICBDb3VudCA9IG4oKQogICksCiAgZ2dwbG90Mjo6YWVzKHggPSBUaW1lLCB5ID0gU3BlY2llcywgY29sb3IgPSBDb3VudCkKKSArIGdncGxvdDI6Omdlb21fcG9pbnQoCiAgc2hhcGUgPSAnLicKKSArIGdncGxvdDI6OnNjYWxlX2NvbG9yX3ZpcmlkaXNfYygKICBkaXJlY3Rpb24gPSAtMQopICsgZ2dwbG90Mjo6ZmFjZXRfZ3JpZCgKICBNb2RpZmllciArIE1vZEludGVuc2l0eSB+IFNwYWNlICsgRGlzdGFuY2UKKSArIGdncGxvdDI6Omdlb21faGxpbmUoCiAgeWludGVyY2VwdCA9IDM0LjUsIGNvbG9yID0gInJlZCIKKQpgYGAKCmBgYHtyfQojIEJydXRlIGZvcmNpbmcgaGVyZSBiZWNhdXNlIEkgd291bGQgcmF0aGVyIHBvc2l0aW9uIG15c2VsZiB0byBtb3ZlIG9uIGlmIHBvc3NpYmxlLgojIFRoaXMgd29ya3MgYmVjYXVzZSBhbGwgb2YgdGhlIHBvb2xzIGFyZSB0aGUgc2FtZSAoZXhjZXB0IHRoYXQgdGhlIG9yaWdpbmFsIGRvZXMgbm90IHVzZSBmYWN0b3JzIGJlY2F1c2Ugc3RyaW5nc0FzRmFjdG9ycyBkaWZmZXJlZCBiZXR3ZWVuIHRoZSBtYWNoaW5lcyBnZW5lcmF0aW5nIHRoZSBzeXN0ZW1zKS4KIyA+IGFsbC5lcXVhbChQb29sc01hdHMkYE1OQS1FeHQxMC1Qb29sTWF0cy1FbnYxMC5SRGF0YWAsIFBvb2xzTWF0cyRgTU5BLUV4dDAuMS1Qb29sTWF0cy1FbnYxMC5SRGF0YWApCiMgWzFdIFRSVUUKIyA+IGFsbC5lcXVhbChQb29sc01hdHMkYE1OQS1FeHQxMC1Qb29sTWF0cy1FbnYxMC5SRGF0YWAsIFBvb2xzTWF0cyRgTU5BLUFycjAuMS1Qb29sTWF0cy1FbnYxMC5SRGF0YWApCiMgWzFdIFRSVUUKIyA+IGFsbC5lcXVhbChQb29sc01hdHMkYE1OQS1FeHQxMC1Qb29sTWF0cy1FbnYxMC5SRGF0YWAsIFBvb2xzTWF0cyRgTU5BLUFycjEwLVBvb2xNYXRzLUVudjEwLlJEYXRhYCkKIyBbMV0gVFJVRQoKU3BlY2llc1ByZXNlbmNlJFNpemVzIDwtIFBvb2xzTWF0cyRgTU5BLUZpcnN0QXR0ZW1wdC1Qb29sTWF0cy1FbnYxMC5SRGF0YWAkUG9vbCRTaXplW1NwZWNpZXNQcmVzZW5jZSRTcGVjaWVzXQoKYGBgCgpgYGB7cn0KZ2dwbG90Mjo6Z2dwbG90KAogIFNwZWNpZXNQcmVzZW5jZSAlPiUgZHBseXI6OmZpbHRlcigKICAgIFNwYWNlICE9ICJSaW5nIgogICkgJT4lIGRwbHlyOjpncm91cF9ieSgKICAgIE1vZGlmaWVyLCBNb2RJbnRlbnNpdHksIFNwYWNlLCBEaXN0YW5jZSwKICAgIFNwZWNpZXMsIFRpbWUsIFNpemVzCiAgKSAlPiUgZHBseXI6OnN1bW1hcmlzZSgKICAgIENvdW50ID0gbigpCiAgKSAlPiUgZHBseXI6OmFycmFuZ2UoCiAgICBTaXplcwogICkgJT4lIGRwbHlyOjp1bmdyb3VwKAogICkgJT4lIGRwbHlyOjptdXRhdGUoCiAgICBTcGVjaWVzID0gZmFjdG9yKFNwZWNpZXMsIGxldmVscyA9IHVuaXF1ZShTcGVjaWVzKSkKICApLAogIGdncGxvdDI6OmFlcyh4ID0gVGltZSwgeSA9IFNwZWNpZXMsIGNvbG9yID0gQ291bnQpCikgKyBnZ3Bsb3QyOjpnZW9tX3BvaW50KAogIHNoYXBlID0gJy4nCikgKyBnZ3Bsb3QyOjpzY2FsZV9jb2xvcl92aXJpZGlzX2MoCikgKyBnZ3Bsb3QyOjpmYWNldF9ncmlkKAogIE1vZGlmaWVyICsgTW9kSW50ZW5zaXR5IH4gU3BhY2UgKyBEaXN0YW5jZQopICsgZ2dwbG90Mjo6Z2VvbV9obGluZSgKICB5aW50ZXJjZXB0ID0gMzQuNSwgY29sb3IgPSAicmVkIgopCmBgYAoKIyMjIFNwZWNpZXMgQWJ1bmRhbmNlCgpgYGB7cn0KIyBnZ3Bsb3QyOjpnZ3Bsb3QoCiMgICBTcGVjaWVzUHJlc2VuY2UgJT4lIGRwbHlyOjpmaWx0ZXIoCiMgICAgIFNwYWNlICE9ICJSaW5nIiwKIyAgICAgVGltZUZsb29yID4gMC4yICMgUmVtb3ZlICJidXJuLWluIiB3aGljaCBoYXMgImltcG9zc2libHkiIGhpZ2ggcHJlc2VuY2UuIAojICAgKSwKIyAgIGdncGxvdDI6OmFlcygKIyAgICAgeCA9IFRpbWVGbG9vciwKIyAgICAgeSA9IEFidW5kYW5jZQojICAgKQojICkgKyBnZ3Bsb3QyOjpnZW9tX2JpbjJkKAojICkgKyBnZ3Bsb3QyOjpzY2FsZV9maWxsX3ZpcmlkaXNfYygKIyApICsgZ2dwbG90Mjo6ZmFjZXRfZ3JpZCgKIyAgIE1vZGlmaWVyICsgTW9kSW50ZW5zaXR5IH4gU3BhY2UgKyBEaXN0YW5jZQojICkgKyBnZ3Bsb3QyOjpzY2FsZV95X2xvZzEwKAojICkgCmdncGxvdDI6OmdncGxvdCgKICBTcGVjaWVzUHJlc2VuY2UgJT4lIGRwbHlyOjpmaWx0ZXIoCiAgICBTcGFjZSAhPSAiUmluZyIKICApICU+JSBkcGx5cjo6bXV0YXRlKAogICAgQWJ1bmRhbmNlID0gcm91bmQoQWJ1bmRhbmNlKQogICkgJT4lIGRwbHlyOjpncm91cF9ieSgKICAgIE1vZGlmaWVyLCBNb2RJbnRlbnNpdHksIFNwYWNlLCBEaXN0YW5jZSwKICAgIEFidW5kYW5jZSwgVGltZQogICkgJT4lIGRwbHlyOjpzdW1tYXJpc2UoCiAgICBDb3VudCA9IG4oKQogICksCiAgZ2dwbG90Mjo6YWVzKHggPSBUaW1lLCB5ID0gQWJ1bmRhbmNlLCBjb2xvciA9IENvdW50KQopICsgZ2dwbG90Mjo6Z2VvbV9wb2ludCgKICBzaGFwZSA9ICcuJwopICsgZ2dwbG90Mjo6c2NhbGVfY29sb3JfdmlyaWRpc19jKAogIHRyYW5zID0gImxvZyIKKSArIGdncGxvdDI6OmZhY2V0X2dyaWQoCiAgTW9kaWZpZXIgKyBNb2RJbnRlbnNpdHkgfiBTcGFjZSArIERpc3RhbmNlCikgKyBnZ3Bsb3QyOjpzY2FsZV95X2xvZzEwKAopCmBgYAoKCiMjIyBTcGVjaWVzIFNpemVzCihSZWNhbGwgdGhhdCB0aGVyZSBpcyBhIHRocmVzaG9sZCBhYm92ZSB3aGljaCB3ZSBoYXZlIGNvbnN1bWVycyBhbmQgYmVsb3cgd2hpY2ggd2UgaGF2ZSBwcm9kdWNlcnMuIFRoaXMgd2lsbCBiZSBkZW5vdGVkIHdpdGggYSBicmlnaHQgbGluZSBhdCB0aGUgdGhyZXNob2xkLikKCmBgYHtyfQojIGdncGxvdDI6OmdncGxvdCgKIyAgIFNwZWNpZXNQcmVzZW5jZSAlPiUgZHBseXI6OmZpbHRlcigKIyAgICAgU3BhY2UgIT0gIlJpbmciLAojICAgICBUaW1lRmxvb3IgPiAwLjIgIyBSZW1vdmUgImJ1cm4taW4iIHdoaWNoIGhhcyAiaW1wb3NzaWJseSIgaGlnaCBwcmVzZW5jZS4gCiMgICApLAojICAgZ2dwbG90Mjo6YWVzKAojICAgICB4ID0gVGltZUZsb29yLAojICAgICB5ID0gU2l6ZXMKIyAgICkKIyApICsgZ2dwbG90Mjo6Z2VvbV9iaW4yZCgKIyAgIGJpbndpZHRoID0gYygwLjEsIDAuMDMpCiMgKSArIGdncGxvdDI6OnNjYWxlX2ZpbGxfdmlyaWRpc19jKAojICkgKyBnZ3Bsb3QyOjpmYWNldF9ncmlkKAojICAgTW9kaWZpZXIgKyBNb2RJbnRlbnNpdHkgfiBTcGFjZSArIERpc3RhbmNlCiMgKSArIGdncGxvdDI6OnNjYWxlX3lfbG9nMTAoCiMgKSArIGdncGxvdDI6Omdlb21faGxpbmUoCiMgICB5aW50ZXJjZXB0ID0gMC4xLCBjb2xvciA9ICJyZWQiCiMgKQoKZ2dwbG90Mjo6Z2dwbG90KAogIFNwZWNpZXNQcmVzZW5jZSAlPiUgZHBseXI6OmZpbHRlcigKICAgIFNwYWNlICE9ICJSaW5nIgogICkgJT4lIGRwbHlyOjpncm91cF9ieSgKICAgIE1vZGlmaWVyLCBNb2RJbnRlbnNpdHksIFNwYWNlLCBEaXN0YW5jZSwKICAgIFNpemVzLCBUaW1lCiAgKSAlPiUgZHBseXI6OnN1bW1hcmlzZSgKICAgIENvdW50ID0gbigpCiAgKSwKICBnZ3Bsb3QyOjphZXMoeCA9IFRpbWUsIHkgPSBTaXplcywgY29sb3IgPSBDb3VudCkKKSArIGdncGxvdDI6Omdlb21fcG9pbnQoCiAgc2hhcGUgPSAnLicKKSArIGdncGxvdDI6OnNjYWxlX2NvbG9yX3ZpcmlkaXNfYygKKSArIGdncGxvdDI6OmZhY2V0X2dyaWQoCiAgTW9kaWZpZXIgKyBNb2RJbnRlbnNpdHkgfiBTcGFjZSArIERpc3RhbmNlCikgKyBnZ3Bsb3QyOjpnZW9tX2hsaW5lKAogIHlpbnRlcmNlcHQgPSAwLjEsIGNvbG9yID0gInJlZCIKKSArIGdncGxvdDI6OnNjYWxlX3lfbG9nMTAoCikKYGBgCgpDb21wYXJlIHdpdGggdGhlIGRpc3RyaWJ1dGlvbiBvZiB0cmFpdHMgYW1vbmdzdCBzcGVjaWVzLgpgYGB7cn0KZ2dwbG90Mjo6Z2dwbG90KAogIFBvb2xzTWF0cyRgTU5BLUZpcnN0QXR0ZW1wdC1Qb29sTWF0cy1FbnYxMC5SRGF0YWAkUG9vbCwKICBnZ3Bsb3QyOjphZXMoCiAgICB4ID0gU2l6ZSwKICAgIGZpbGwgPSBUeXBlCiAgKQopICsgZ2dwbG90Mjo6Z2VvbV9oaXN0b2dyYW0oI2dncGxvdDI6Omdlb21fZGVuc2l0eSgKICAjYWxwaGEgPSAwLjUsIGFkanVzdCA9IDEvMTAKICBiaW5zID0gMTAwCikgKyBnZ3Bsb3QyOjpzY2FsZV94X2xvZzEwKCkgKyBnZ3Bsb3QyOjpjb29yZF9mbGlwKCkKYGBgCgojIyBFdmVudHMgey50YWJzZXR9IAoKIyMjIFByZXBhcmF0aW9uCgpgYGB7cn0KQ2FsY3VsYXRlX0V2ZW50cyA8LSBmdW5jdGlvbihyZXN1bHQsIGFidW5kYW5jZVRpbWUgPSBkaXZpZGVfdGltZV9ieSwgdGhpbm5pbmcgPSBieV9mb3JfdGhpbm5pbmcpIHsKICBhYnVuZCA8LSByZXN1bHQkQWJ1bmRhbmNlCiAgYWJ1bmRbLCAtMV0gPC0gYWJ1bmRbLCAtMV0gPiAwICMgUHJlc2VuY2UtQWJzZW5jZQogIGFidW5kRGlmZiA8LSBhcHBseShhYnVuZFssIC0xXSwgMiwgZGlmZikgCiAgIyBBcnJpdmFsICgxKSBFbGltaW5hdGlvbiAoLTEpCiAgIyBpZiBhcnJpdmFsIGF0IHRpbWUgOTMsCiAgIyA5Mm5kIGVudHJ5IGlzIDEuCiAgYWJ1bmREaWZmIDwtIGNiaW5kKAogICAgYWJ1bmRbLTEsIDFdICogYWJ1bmRhbmNlVGltZSwgYWJ1bmREaWZmCiAgKQogIAogIEV2ZW50cyA8LSBsYXBwbHkoCiAgICAxOm5jb2woYWJ1bmREaWZmWywgLTFdKSwKICAgIGZ1bmN0aW9uKGksIGFiLCB0bSwgc3ApIHsKICAgICAgYXJyaXZhbHMgPC0gd2hpY2goYWJbLCBpXSA9PSAxKQogICAgICBleHRpbmN0cyA8LSB3aGljaChhYlssIGldID09IC0xKQogICAgICAKICAgICAgaWYgKGxlbmd0aChhcnJpdmFscykgKyBsZW5ndGgoZXh0aW5jdHMpID09IDApIHsKICAgICAgICByZXR1cm4oTlVMTCkKICAgICAgfSAKICAgICAgCiAgICAgIGRhdGEuZnJhbWUoCiAgICAgICAgVGltZXMgPSBjKHRtW2Fycml2YWxzXSwgdG1bZXh0aW5jdHNdKSwKICAgICAgICBTcGVjaWVzID0gKChpIC0gMSkgJSUgc3ApICsgMSwgIyAxOjEwMDAgLT4gMToxMDAKICAgICAgICBFbnZpcm9ubWVudCA9ICgoaSAtIDEpICUvJSBzcCkgKyAxLAogICAgICAgIFR5cGUgPSBjKHJlcCgiQXJyaXZhbCIsIGxlbmd0aChhcnJpdmFscykpLAogICAgICAgICAgICAgICAgICByZXAoIkV4dGluY3QiLCBsZW5ndGgoZXh0aW5jdHMpKSksCiAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFCiAgICAgICkKICAgIH0sCiAgICBhYiA9IGFidW5kRGlmZlssIC0xXSwKICAgIHRtID0gYWJ1bmREaWZmWywgMV0sCiAgICBzcCA9IG5jb2woYWJ1bmREaWZmWywgLTFdKSAvIHJlc3VsdCROdW1FbnZpcm9ubWVudHMjLAogICAgI25lID0gcmVzdWx0JE51bUVudmlyb25tZW50cwogICkgJT4lIGRwbHlyOjpiaW5kX3Jvd3MoCiAgKSAlPiUgZHBseXI6OmFycmFuZ2UoCiAgICBUaW1lcywgU3BlY2llcywgRW52aXJvbm1lbnQsIFR5cGUKICApCiAgCiAgIyBOb3cgd2UgY2hlY2sgdG8gc2VlIHdoaWNoIGV2ZW50cyBhcmUgaW4gdGhlIHJlY29yZC4KICAjIE5vdGUgdGhhdCwgZHVlIHRvIHRoaW5uaW5nLCB3ZSBkbyBoYXZlIGEgdGhlb3JldGljYWwKICAjIHByb2JsZW06IGFuIGV2ZW50IHRpbWUgbWlnaHQgYmUgbWlzcmVjb3JkZWQgd2hlbgogICMgZXh0cmFjdGVkIGZyb20gdGhlIGFidW5kYW5jZSByZWNvcmQuCiAgIyBIZW5jZSB3ZSBjYW5ub3QganVzdCB1c2UgZmlsdGVyaW5nIGpvaW4gb3BlcmF0aW9ucy4KICAjIFNpbmNlIHdlIGtub3cgdGhlIG1heGltdW0gdGltZSBzdGVwIHNpemUgYW5kIHRoZQogICMgdGhpbm5pbmcsIHdlIGtub3cgdGhhdCB3ZSBzaG91bGQgZGV0ZWN0IGEgY2hhbmdlCiAgIyB3aXRoaW4gKHRoaW5uaW5nKSAqIChtYXguIHRpbWUgc3RlcCBzaXplKSB1bml0cy4KICBtYXhpbXVtR2FwIDwtIHRoaW5uaW5nICogcmVzdWx0JFBhcmFtZXRlcnMkTWF4aW11bVRpbWVTdGVwCiAgCiAgcmVzdWx0JEV2ZW50cyRUeXBlIDwtIGFzLmNoYXJhY3RlcihyZXN1bHQkRXZlbnRzJFR5cGUpCiAgCiAgIyBDb25uZWN0IGFsbCBzYW1lIGV2ZW50LCBldmVuIHdpdGggZGlmZmVyZW50IHRpbWVzLgogICMgUmVtb3ZlIHRob3NlIHRoYXQgY2Fubm90IGJlIHRoZSBzYW1lIGV2ZW50LgogICMgVHJlYXQgdGhpcyBhcyB0aGUgbGlzdCBvZiBOZXV0cmFsIEV2ZW50cyB0aGF0CiAgIyBhY3R1YWxseSBoYXBwZW5lZC4KICBFdmVudHNPZmZpY2lhbCA8LSByZXN1bHQkRXZlbnRzICU+JSBkcGx5cjo6bGVmdF9qb2luKAogICAgRXZlbnRzLCAKICAgIGJ5ID0gYygiU3BlY2llcyIsICJFbnZpcm9ubWVudCIsICJUeXBlIikKICApICU+JSBkcGx5cjo6bXV0YXRlKAogICAgIyBkcGx5cjo6ZmlsdGVyKCAjIEZpbHRlcmluZyBkb2VzIG5vdCB3b3JrLgogICAgIyBXZSBhcmUgc2VlaW5nIGxvc3NlcyBvZiBhYm91dCA1MCUgd2l0aCBmaWx0ZXIuCiAgICAjICJSb3dzIGluIHggd2l0aCBubyBtYXRjaCBpbiB5IHdpbGwgaGF2ZSBOQSB2YWx1ZXMgaW4gdGhlIG5ldyBjb2x1bW5zLiIgCiAgICAjIC0+IFRpbWVzLnkgd2lsbCBiZSBOQS4KICAgICMgVGltZXMueSBpcyB0aGUgZGV0ZWN0ZWQgdGltZS4KICAgICMgVGltZXMueCBpcyB0aGUgcmVjb3JkZWQgYWN0aW9uJ3MgdGltZS4KICAgICMgTm90ZSB0aGF0IHdlIGNhbiBnZXQgZmFsc2UgcmVhZGluZ3MgZnJvbSBzdWJ0cmFjdGluZyB0d28gYWxtb3N0IHRoZSBzYW1lIAogICAgIyBudW1iZXJzLCBzbyB3ZSBuZWVkIHRvIGFwcGVhbCB0byBtYWNoaW5lIHByZWNpc2lvbi4gCiAgICAjIFNlZSBhbGwuZXF1YWwncyB0b2xlcmFuY2UgYXJndW1lbnQuCiAgICBgVGltZXMueWAgPSBkcGx5cjo6Y2FzZV93aGVuKAogICAgICBpcy5uYShgVGltZXMueWApIH4gYXMuZG91YmxlKE5BKSwKICAgICAgKAogICAgICBgVGltZXMueWAgLSBgVGltZXMueGAgPCBtYXhpbXVtR2FwICsgc3FydCguTWFjaGluZSRkb3VibGUuZXBzKSAmIAogICAgICAgIGBUaW1lcy55YCAtIGBUaW1lcy54YCA+PSAtc3FydCguTWFjaGluZSRkb3VibGUuZXBzKSkgfiBgVGltZXMueWAsCiAgICAgIFRSVUUgfiBhcy5kb3VibGUoTkEpCiAgICApCiAgKSAlPiUgZHBseXI6Omdyb3VwX2J5KAogICAgYFRpbWVzLnhgLCBTcGVjaWVzLCBFbnZpcm9ubWVudCwgVHlwZSwgU3VjY2VzcwogICAgIyBEb24ndCBkaXNjYXJkIFN1Y2Nlc3MsIG90aGVycyBhcmUgdHJ1ZSBncm91cHMuCiAgICAjIFdlIHdhbnQgdG8gcHJlc2VydmUgdGhlIGZpcnN0IGBUaW1lcy55YAogICAgIyAoaW4gY2FzZSBhbiBldmVudCBoYXBwZW5zIG11bHRpcGxlIHRpbWVzKQogICAgIyBidXQgaWYgdGhlcmUgYXJlIG5vIG51bWVyaWNzLAogICAgIyB3ZSBpbnN0ZWFkIHdhbnQgdG8ga2VlcCBvbmUgb2YgdGhlIE5Bcy4KICApICU+JSBkcGx5cjo6c3VtbWFyaXNlKAogICAgYFRpbWVzLnlgID0gaWYgKGxlbmd0aChuYS5vbWl0KGBUaW1lcy55YCkpID09IDApIE5BIGVsc2UgbWluKGBUaW1lcy55YCwgbmEucm0gPSBUUlVFKQogICkgJT4lIGRwbHlyOjp1bmdyb3VwKAogICkgJT4lIGRwbHlyOjpyZW5hbWUoCiAgICBUaW1lSW1wbGVtZW50ZWQgPSBgVGltZXMueGAsCiAgICBUaW1lRGV0ZWN0ZWQgPSBgVGltZXMueWAKICApCiAgCiAgIyBFdmVudHMgdGhhdCB3ZXJlIG5vdCBkZXRlY3RlZCBidXQgd2VyZSBzdWNjZXNzZnVsLgogICMgSWYgdGhpcyBpcyB0aGUgY2FzZSwgc29tZXRoaW5nIGhhcHBlbmVkIGFuZCB3YXMgCiAgIyB1bmRvbmUgaW4gdGhlIHNhbWUgdGltZXNwYW4uCiAgIyBUaGlzIG1pZ2h0IGhhcHBlbiBkdWUgdG8gYXJyaXZhbHMgZnJvbSBhZGphY2VudCAKICAjIHBhdGNoZXMuCiAgIyBJLmUuIGVsaW1pbmF0aW9uIGNvaW5jaWRpbmcgd2l0aCBhcnJpdmFsIG9yIAogICMgYXJyaXZhbCBiZWluZyB0b28gZGlzc2lwYXRlZCBieSBkaXNwZXJzYWwuCiAgIyBUaGlzIHByb2JhYmx5IHNob3VsZG4ndCBoYXBwZW4gaW4gdGhlIGRpc2Nvbm5lY3RlZCBzeXN0ZW0uCiAgRXZlbnRzTm90RGV0ZWN0ZWQgPC0gRXZlbnRzT2ZmaWNpYWwgJT4lIGRwbHlyOjpmaWx0ZXIoCiAgICBpcy5uYShUaW1lRGV0ZWN0ZWQpLCBTdWNjZXNzID09IFRSVUUKICAjICkgJT4lIGRwbHlyOjpzZWxlY3QoCiAgIyAgIC1gVGltZXMueWAKICAjICkgJT4lIGRwbHlyOjpyZW5hbWUoCiAgIyAgIFRpbWVzID0gYFRpbWVzLnhgCiAgKSAlPiUgZHBseXI6Om11dGF0ZSgKICAgIE5ldXRyYWwgPSBUUlVFLAogICAgRGV0ZWN0ZWQgPSBGQUxTRQogICkKICAKICAjIEV2ZW50cyB0aGF0IHdlcmUgZGV0ZWN0ZWQgYW5kIHdlcmUgc3VjY2Vzc2Z1bC4gJ1RydWUgUG9zaXRpdmVzJwogICMgV2UgcmVjb3JkZWQgdGhlbSBhcyBoYXZpbmcgaGFwcGVuZWQgaW4gRXZlbnRzIGFuZCBBYnVuZGFuY2UuCiAgIyBUaGVzZSBhcmUgYWxzbyBOZXV0cmFsIHdpdGggaGlnaCBwcm9iYWJpbGl0eS4KICBFdmVudHNEZXRlY3RlZCA8LSBFdmVudHNPZmZpY2lhbCAlPiUgZHBseXI6OmZpbHRlcigKICAgICFpcy5uYShUaW1lRGV0ZWN0ZWQpLCBTdWNjZXNzID09IFRSVUUKICAgICMgKSAlPiUgZHBseXI6OnNlbGVjdCgKICAgICMgIyBXZSBrZWVwIFRpbWVzLnkgZm9yIGNvbXBhcmlzb24gd2l0aCBFdmVudHMuCiAgICAjICAgLWBUaW1lcy54YAogICAgIyApICU+JSBkcGx5cjo6cmVuYW1lKAogICAgIyAgIFRpbWVzID0gYFRpbWVzLnlgCiAgICApICU+JSBkcGx5cjo6bXV0YXRlKAogICAgICBOZXV0cmFsID0gVFJVRSwKICAgICAgRGV0ZWN0ZWQgPSBUUlVFCiAgICApCiAgCiAgIyBFdmVudHMgdGhhdCB3ZXJlIG5vdCBkZXRlY3RlZCBhbmQgd2VyZSBub3Qgc3VjY2Vzc2Z1bC4gJ1RydWUgTmVnYXRpdmVzJwogICMgQWxzbyBFdmVudHMgdGhhdCB3ZXJlIGRldGVjdGVkIGFuZCB3ZXJlIG5vdCBzdWNjZXNzZnVsLiAnRmFsc2UgUG9zaXRpdmVzJz8KICAjIFRoZSBkZXRlY3Rpb24gbXVzdCBiZSBvZiBhIGRpZmZlcmVudCBldmVudCBpZiB0aGUgZXZlbnQKICAjIHdlIHJlY29yZGVkIHdhcyB1bnN1Y2Nlc3NmdWwgYWZ0ZXIgYWxsLgogIEV2ZW50c0ZhaWxlZCA8LSBFdmVudHNPZmZpY2lhbCAlPiUgZHBseXI6OmZpbHRlcigKICAgICNpcy5uYShgVGltZXMueWApLCAKICAgIFN1Y2Nlc3MgIT0gVFJVRQogICAgIyApICU+JSBkcGx5cjo6c2VsZWN0KAogICAgIyAgIC1gVGltZXMueWAKICAgICMgKSAlPiUgZHBseXI6OnJlbmFtZSgKICAgICMgICBUaW1lcyA9IGBUaW1lcy54YAogICAgKSAlPiUgZHBseXI6Om11dGF0ZSgKICAgICAgTmV1dHJhbCA9IFRSVUUsCiAgICAgIERldGVjdGVkID0gRkFMU0UKICAgICkKICAKICAjIFNvIHdlIGhhdmUgZXZlbnRzIHRoYXQgd2VyZSBkZXRlY3RlZCBidXQgbm90IHN1Y2Nlc3NmdWwuCiAgIyBTdWNoIGV2ZW50cyBzaG91bGQgcHJvYmFibHkgYmUgbGlzdGVkIHR3aWNlOiAKICAjICAgb25jZSBhcyBuZXV0cmFsICh0aGUgZmFpbHVyZSwgYWJvdmUpCiAgIyAgIG9uY2UgYXMgbm9uLW5ldXRyYWwgKHRoZSBkZXRlY3RlZCBldmVudCwgYmVsb3cpLgogICMgKE5vdGUgRXZlbnRzIGFyZSBmcm9tIGFidW5kYW5jZSBhbmQgdGh1cyBkZXRlY3RlZC4pCiAgRXZlbnRzTm90T2ZmaWNpYWwgPC0gRXZlbnRzICU+JSBkcGx5cjo6cmVuYW1lKAogICAgVGltZURldGVjdGVkID0gVGltZXMKICApICU+JSBkcGx5cjo6YW50aV9qb2luKAogICAgRXZlbnRzRGV0ZWN0ZWQsIGJ5ID0gYygiVGltZURldGVjdGVkIiwgIlNwZWNpZXMiLCAiRW52aXJvbm1lbnQiLCAiVHlwZSIpCiAgKSAgJT4lIGRwbHlyOjptdXRhdGUoCiAgICBTdWNjZXNzID0gVFJVRSwKICAgIE5ldXRyYWwgPSBGQUxTRSwKICAgIERldGVjdGVkID0gVFJVRQogICkgCiAgCiAgIyBUaGUgcmVtYWluZGVyIG9mIGV2ZW50IHNwYWNlIGlzIGV2ZW50cyB0aGF0IGFyZQogICMgbm90IG5ldXRyYWwgYW5kIG5vdCBzdWNjZXNzZnVsIG9yIAogICMgZXZlbnRzIHRoYXQgd2VyZSBub3QgaW1wbGVtZW50ZWQuCiAgCiAgIyBOb3RlIHRoZW4gdGhhdCwgaWYgZXZlcnl0aGluZyB3ZW50IHdlbGwKICBzdG9waWZub3QobnJvdyhFdmVudHNOb3RPZmZpY2lhbCkgKyBucm93KEV2ZW50c0RldGVjdGVkKSA9PSBucm93KEV2ZW50cyksCiAgICAgICAgICAgIG5yb3coRXZlbnRzRGV0ZWN0ZWQpICsgbnJvdyhFdmVudHNGYWlsZWQpICsgbnJvdyhFdmVudHNOb3REZXRlY3RlZCkgPT0gbnJvdyhyZXN1bHQkRXZlbnRzKSkKCiAgcmV0dXJuKGRwbHlyOjpiaW5kX3Jvd3MoCiAgICBFdmVudHNEZXRlY3RlZCwKICAgIEV2ZW50c05vdERldGVjdGVkLAogICAgRXZlbnRzRmFpbGVkLAogICAgRXZlbnRzTm90T2ZmaWNpYWwKICApICU+JSBkcGx5cjo6bXV0YXRlKAogICAgVGltZXMgPSBkcGx5cjo6Y2FzZV93aGVuKAogICAgICAhaXMubmEoVGltZUltcGxlbWVudGVkKSB+IFRpbWVJbXBsZW1lbnRlZCwKICAgICAgIWlzLm5hKFRpbWVEZXRlY3RlZCkgfiBUaW1lRGV0ZWN0ZWQKICAgICkKICApICU+JSBkcGx5cjo6YXJyYW5nZShUaW1lcywgRW52aXJvbm1lbnQsIFNwZWNpZXMsIFR5cGUpKQp9CmBgYApgYGB7ciwgZXZhbD1UUlVFfQpFdmVudHMgPC0gIHNhcHBseSgKICBVU0UuTkFNRVMgPSBUUlVFLCBzaW1wbGlmeSA9IEZBTFNFLAogIFJlc3VsdHMsIGZ1bmN0aW9uKHJlc3VsdCkgewogICAgaWYgKGxlbmd0aChyZXN1bHQpID09IDEgJiYgaXMubmEocmVzdWx0KSkgewogICAgICAjIFByb2JsZW0gY2FzZS4KICAgICAgcmV0dXJuKE5BKQogICAgfQogICAgIyBwcmludChwYXN0ZSgiQ2FsY3VsYXRpbmciLCBTeXMudGltZSgpKSkKICAgIAogICAgIyBDYWxjdWxhdGUgdGhlIGRpdmVyc2l0eS4KICAgICMgV2Ugd2lsbCBuZWVkIHRvIGV4dHJhY3QgdGhlIHN5c3RlbSBwcm9wZXJ0aWVzIGZyb20KICAgICMgdGhlIGZpbGUgbmFtZXMgd2hpY2ggd2UgY2FycnkgdGhyb3VnaCB1c2luZyBzYXBwbHkuCiAgICByZXR1cm4oQ2FsY3VsYXRlX0V2ZW50cyhyZXN1bHQpKQogIH0KKQpgYGAKCmBgYHtyfQpFdmVudHMgPC0gbGFwcGx5KDE6bGVuZ3RoKEV2ZW50cyksCiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oaSwgZGYsIG5tKSB7CiAgICAgICAgICAgICAgICAgICAgICBkZltbaV1dICU+JSBtdXRhdGUoCiAgICAgICAgICAgICAgICAgICAgICAgIFNpbXVsYXRpb24gPSBubVtpXQogICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgIH0sIAogICAgICAgICAgICAgICAgICAgIGRmID0gRXZlbnRzLAogICAgICAgICAgICAgICAgICAgIG5tID0gbmFtZXMoRXZlbnRzKSkKYGBgCgpgYGB7cn0KRXZlbnRzU3VjY2Vzc2VzIDwtIGxhcHBseShFdmVudHMsIGZ1bmN0aW9uKEV2ZW50KSB7CiAgRXZlbnQgJT4lIGRwbHlyOjpmaWx0ZXIoCiAgICBTdWNjZXNzID09IFRSVUUKICApICU+JSBkcGx5cjo6Z3JvdXBfYnkoCiAgICBFbnZpcm9ubWVudAogICkgJT4lIGRwbHlyOjphcnJhbmdlKAogICAgVGltZXMKICApICU+JSBkcGx5cjo6bXV0YXRlKAogICAgSW50ZXJhcnJpdmFsVGltZSA9IFRpbWVzIC0gbGFnKFRpbWVzKSwgCiAgICBEeW5hbWljID0gIU5ldXRyYWwsIAogICAgU2VxdWVuY2UgPSBjdW1zdW0oTmV1dHJhbCkKICApICU+JSBkcGx5cjo6Z3JvdXBfYnkoCiAgICBFbnZpcm9ubWVudCwgU2VxdWVuY2UKICApICU+JSBkcGx5cjo6bXV0YXRlKAogICAgRXZlbnRJblNlcXVlbmNlID0gY3Vtc3VtKER5bmFtaWMpCiAgKQp9KSAKYGBgCgpgYGB7cn0KRXZlbnRzIDwtIGxhcHBseShFdmVudHMsIGZ1bmN0aW9uKEV2ZW50KSB7CiAgRXZlbnQgJT4lIGRwbHlyOjpncm91cF9ieSgKICAgIEVudmlyb25tZW50CiAgKSAlPiUgZHBseXI6OmFycmFuZ2UoCiAgICBUaW1lcwogICkgJT4lIGRwbHlyOjptdXRhdGUoCiAgICBJbnRlcmFycml2YWxUaW1lID0gVGltZXMgLSBsYWcoVGltZXMpLCAKICAgIER5bmFtaWMgPSAhTmV1dHJhbCwgCiAgICBTZXF1ZW5jZSA9IGN1bXN1bShOZXV0cmFsKQogICkgJT4lIGRwbHlyOjpncm91cF9ieSgKICAgIEVudmlyb25tZW50LCBTZXF1ZW5jZQogICkgJT4lIGRwbHlyOjptdXRhdGUoCiAgICBFdmVudEluU2VxdWVuY2UgPSBjdW1zdW0oRHluYW1pYykKICApCn0pIApgYGAKCmBgYHtyfQpFdmVudHMgPC0gZHBseXI6OmxlZnRfam9pbigKICBkcGx5cjo6YmluZF9yb3dzKEV2ZW50cyksCiAgUHJvcGVydGllcywKICBieSA9IGMoIlNpbXVsYXRpb24iID0gIkZ1bGxOYW1lIikKKQpgYGAKCmBgYHtyfQpFdmVudHNTdWNjZXNzZXMgPC0gZHBseXI6OmxlZnRfam9pbigKICBkcGx5cjo6YmluZF9yb3dzKEV2ZW50c1N1Y2Nlc3NlcyksCiAgUHJvcGVydGllcywKICBieSA9IGMoIlNpbXVsYXRpb24iID0gIkZ1bGxOYW1lIikKKQpgYGAKCmBgYHtyLCBldmFsPUZBTFNFfQpFdmVudHMgPC0gRXZlbnRzICU+JSBkcGx5cjo6bXV0YXRlKAogIERpc3RhbmNlID0gZHBseXI6OmNhc2Vfd2hlbigKICAgIGlzLm5hKERpc3RhbmNlKSB+ICIxZSswMCIsCiAgICBUUlVFIH4gRGlzdGFuY2UKICApCikKYGBgCgpgYGB7ciwgZXZhbD1GQUxTRX0KRXZlbnRzU3VjY2Vzc2VzIDwtIEV2ZW50c1N1Y2Nlc3NlcyAlPiUgZHBseXI6Om11dGF0ZSgKICBEaXN0YW5jZSA9IGRwbHlyOjpjYXNlX3doZW4oCiAgICBpcy5uYShEaXN0YW5jZSkgfiAiMWUrMDAiLAogICAgVFJVRSB+IERpc3RhbmNlCiAgKQopCmBgYAoKPCEtLQoKIyMjIEFuYWx5c2lzIHsudGFic2V0fQoKIyMjIyBTZXR1cCBhbmQgTmV1dHJhbGl0eQpGaXJzdCwgc29tZSBub3Rlcy4KQWxsIG5ldXRyYWwgZXZlbnRzIGFyZSwgYXQgdGhpcyBwb2ludCwgZ2VuZXJhdGVkIGZyb20gZXhwb25lbnRpYWwgZGlzdHJpYnV0aW9ucyB3aXRoIHVuaWZvcm1seSBhdCByYW5kb20gd2l0aCByZXBsYWNlbWVudCBzZWxlY3Rpb24gZnJvbSB0aGUgcG9zc2libGUgZW52aXJvbm1lbnRzIGFuZCBzcGVjaWVzLgpUaGUgbnVtYmVyIG9mIGFycml2YWwgYW5kIGV4dGluY3Rpb24gZXZlbnRzIGFyZSBmaXhlZCBidXQgYWxsIGV2ZW50cyBhcmUgb3RoZXJ3aXNlIGdlbmVyYXRlZCBpbmRlcGVuZGVudGx5IG9mIGVhY2ggb3RoZXIuClRoZSByYXRlIGZvciBhcnJpdmFsIGV2ZW50cyBhbmQgcmF0ZSBmb3IgZXh0aW5jdGlvbiBldmVudHMgYXJlIGJvdGggZml4ZWQgYWhlYWQgb2YgdGltZSBhbmQgY2FuIHZhcnkuIFRoZXkgaGF2ZSBiZWVuIGNvdXBsZWQgdG8gdGhlIGNoYXJhY3RlcmlzdGljIHRpbWUgb2YgdGhlIGxhcmdlc3QgcGVydHVyYmF0aW9uIG9mIHRoZSBpbnRlcmFjdGlvbiBtYXRyaWNlcyBhbmQgYXJlIGVpdGhlciB0aGF0IHZhbHVlIChkZWZhdWx0KSBvciBhIGZhY3RvciBvZiB0ZW4gYmlnZ2VyIG9yIHNtYWxsZXIgdGhhbiB0aGF0IHZhbHVlLgoKQnkgdGhlIG5hdHVyZSBvZiB0aGUgc2V0dXAsIHdlIHNob3VsZCBleHBlY3QgdGhhdCB0aGUgZnVsbCBsaXN0IG9mIGV2ZW50cyB3aWxsIGJlaGF2ZSBhcyBhIGNvbWJpbmF0aW9uIG9mIGV4cG9uZW50aWFsIGRpc3RyaWJ1dGlvbnMgZG9lcy4KSXQgaXMgd2VsbC1rbm93biB0aGF0IHRoZSBtaW5pbXVtIG9mIGV4cG9uZW50aWFscyBpcyBhbiBleHBvbmVudGlhbCB3aXRoIHJhdGUgZXF1YWwgdG8gdGhlIHN1bSBvZiB0aGUgcmF0ZXMuCkZ1cnRoZXIgd2UgYXJlIGV4cGxvaXRpbmcgdGhlIG1lbW9yeWxlc3NuZXNzIHRvIHJlcGVhdGVkbHkgZHJhdyBmcm9tIHRoZSBkaXN0cmlidXRpb24sIHNvIHRoaXMgcmF0ZSBjYW4gYmUgdGhvdWdodCBvZiBhcyBwcmVzZXJ2ZWQgdGhyb3VnaG91dC4KCk91ciBwbGFuIGlzIHRodXMgdG8gZml0IHRoZSBuZXV0cmFsIGRpc3RyaWJ1dGlvbnMsIHNlZSBob3cgdGhleSBhcmUgZmlsdGVyZWQgdGhyb3VnaCB0aGUgZWNvbG9naWNhbCBkeW5hbWljcywgYW5kIHRoZW4gc2VlIGhvdyB0aGUgZmluYWwgZXZlbnQgdGltZXMgaW5jbHVkaW5nIGJvdGggbmV1dHJhbCBhbmQgbm9uLW5ldXRyYWwgZXZlbnRzIGNvbXBhcmUuCgotLT4gCmBgYHtyLCBldmFsPUZBTFNFfQojIFJldHJpZXZlIHRoZSBDaGFyYWN0ZXJpc3RpYyBSYXRlIHVzZWQuCiMgU2luY2UgYWxsIG9mIHRoZSBQb29scyBhbmQgTWF0cmljZXMgYXJlIHRoZSBzYW1lLCB0aGV5IGFsbCBoYXZlIHRoZSBzYW1lIGNoYXJhY3RlcmlzdGljIHJhdGUuCiMgVGhlcmUgaXMgYSBmdWRnZSBoZXJlLiBMb29raW5nIGJhY2sgYXQgdGhlIGNvZGUsIHRoZSBmaXJzdCBtYXRyaXggd2FzIHVzZWQsIHJhdGhlciB0aGFuIGxvb2tpbmcgb3ZlciBhbGwgb2YgdGhlIG1hdHJpY2VzLCBidXQgd2Ugbm90ZSB0aGF0IHRoZSByZXN1bHRzIGFyZSBlc3NlbnRpYWxseSB0aGUgc2FtZS4KIyBQZXJoYXBzIHNvbWV0aGluZyB0byBiZSBtb3JlIGNhcmVmdWwgb2YgZm9yIHRoZSBuZXh0IHJvdW5kIG9mIHNpbXVsYXRpb25zLi4uCkNoYXJhY3RlcmlzdGljUmF0ZSA8LSBtYXgoYWJzKGVpZ2VuKFBvb2xzTWF0c1tbMV1dJEludGVyYWN0aW9uTWF0cmljZXMkTWF0c1tbMV1dKSR2YWx1ZXMpKQpgYGAKCjwhLS0gTm90ZSB0aGF0LCB3aGlsZSBjb25zaWRlcmluZyBhcnJpdmFscyBhbmQgZXh0aW5jdGlvbnMgdG9nZXRoZXIsIHdlIHdpbGwgbmVlZCB0byBkb3VibGUgdGhlIGNoYXJhY3RlcmlzdGljIHJhdGUuIAoKQW4gZXhhbXBsZSBhbmFseXNpcyBvZiBza2V3bmVzcyBhbmQga3VydG9zaXMgb2YgdGhlIGludGVyLWV2ZW50IHRpbWVzOiAtLT4KYGBge3IsIGV2YWw9RkFMU0V9CnNldC5zZWVkKDEpCmV4YW1wbGVEYXRhIDwtIEV2ZW50c1tbMl1dICU+JSBkcGx5cjo6ZmlsdGVyKE5ldXRyYWwpICU+JSBkcGx5cjo6YXJyYW5nZShUaW1lcykgJT4lIHB1bGwoVGltZXMpICU+JSBkaWZmCmZpdGRpc3RycGx1czo6ZGVzY2Rpc3QoZXhhbXBsZURhdGEsIGJvb3QgPSAxMDApCmBgYAoKPCEtLWNsZWFybHkgYSBiZXRhIGRpc3RyaWJ1dGlvbiBpcyBpbmFwcHJvcHJpYXRlLCBidXQgd2UgZG8gc2VlIHRoYXQgV2VpYnVsbCwgZ2FtbWEsIGFuZCBleHBvbmVudGlhbCBkaXN0cmlidXRpb25zIHNlZW0gbGlrZSB0aGV5IGNvdWxkIGJlIGFwcHJvcHJpYXRlLgpPbiB0aGUgb3RoZXIgaGFuZCwganVzdCBhcyB0aGUgYmV0YSBkaXN0cmlidXRpb24gbGFja3MgYXBwcm9wcmlhdGUgc3VwcG9ydCwgc28gdG9vIGRvZXMgdGhlIGdhbW1hICh3ZSBoYXZlIGEgZmV3IGVmZmVjdGl2ZWx5IDAncykuCkZvciB0aGUgbGF0dGVyLCB3ZSBtYXkgaGF2ZSB0byB0cnkgcmVwbGFjaW5nIG91ciAwJ3MuCk9mIGNvdXJzZSwgaXQgaXMgd29ydGggbm90aW5nIHRoYXQgZXhwb25lbnRpYWwgZGlzdHJpYnV0aW9ucyBsaWUgb24gdGhlIGJvdW5kYXJ5IHdpdGggaGVhdnktdGFpbGVkIGRpc3RyaWJ1dGlvbnMsIHNvIGl0IG1pZ2h0IG1ha2Ugc2Vuc2UgdG8gdHJ5IHBvd2VyIGxhdyBkaXN0cmlidXRpb25zLCBhbHRob3VnaCBpdCBkb2VzIG5vdCBzZWVtIHRlcnJpYmx5IGNvbnNpc3RlbnQgd2l0aCBhIGxvZy1ub3JtYWwgZGlzdHJpYnV0aW9uLgpUaGlzIG1vdGl2YXRlcyB0aGUgdXNhZ2Ugb2YgdGhlIGBwb3dlUmxhd2AgcGFja2FnZSwgd2hpY2ggY29udGFpbnMgZnVuY3Rpb25zIGRlcml2ZWQgZnJvbSBDbGF1c2V0LCBTaGFsaXppIGFuZCBOZXdtYW4ncyB3b3JrIG9uIGZpdHRpbmcgcG93ZXIgbGF3IGRpc3RyaWJ1dGlvbnMuCldlIHdpbGwgdXNlIGBmaXRkaXN0cnBsdXNgIGZvciBub24taGVhdnkgdGFpbGVkIGRpc3RyaWJ1dGlvbnMgYW5kIGBwb3dlUmxhd2AgZm9yIHRoZSBoZWF2eS10YWlsZWQgZGlzdHJpYnV0aW9ucy4KTm90ZSB0aGF0IHdlIG5lZWQgdG8gdXNlIHRoZSBzYW1lIGRhdGEgdG8gbWFrZSBnb29kIGNvbXBhcmlzb25zLgpXaGlsZSB0aGUgZXhwb25lbnRpYWwgY2FuIGJlIGZpdCB0byBhIGRhdGEgc2V0IHdpdGggMCdzLCB0aGUgZ2FtbWEgYW5kIFdlaWJ1bGwgKGFuZCBgcG93ZVJsYXdgIHBhY2thZ2UgZGlzdHJpYnV0aW9ucykgY2Fubm90LCBzbyB3ZSByZXBsYWNlIDAncyB3aXRoIG1hY2hpbmUgcHJlY2lzaW9uLgooV0FSTklORzogdGhlIGBwb3dlUmxhd2AgcGFja2FnZSBjYW4gYmUgcXVpdGUgdGltZSBpbnRlbnNpdmUgZm9yIGZpdHRpbmcuIENhdXRpb24gaXMgYWR2aXNlZC4pIC0tPgoKYGBge3IsIGV2YWw9RkFMU0V9CmNlbnNEYXRhIDwtIGlmZWxzZShleGFtcGxlRGF0YSA9PSAwLCAuTWFjaGluZSRkb3VibGUuZXBzLCBleGFtcGxlRGF0YSkKZXhhbXBsZUZpdHNOb3RIZWF2eSA8LSBsaXN0KAogIGV4cCA9IGZpdGRpc3RycGx1czo6Zml0ZGlzdChjZW5zRGF0YSwgImV4cCIsIG1ldGhvZCA9ICJtbGUiKSwKICBnYW1tYSA9IGZpdGRpc3RycGx1czo6Zml0ZGlzdChjZW5zRGF0YSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJnYW1tYSIsIG1ldGhvZCA9ICJtbGUiKSwKICB3ZWlidWxsID0gZml0ZGlzdHJwbHVzOjpmaXRkaXN0KGNlbnNEYXRhLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIndlaWJ1bGwiLCBtZXRob2QgPSAibWxlIikKKQpgYGAKYGBge3IsIGV2YWw9RkFMU0V9CmV4YW1wbGVGaXRzSGVhdnkgPC0gbGFwcGx5KAogICAgYyhwb3dlUmxhdzo6Y29uZXhwLCBwb3dlUmxhdzo6Y29ubG5vcm0sIHBvd2VSbGF3Ojpjb25wbCwgcG93ZVJsYXc6OmNvbndlaWJ1bGwpLCBmdW5jdGlvbihmKSB7ZiRuZXcoY2Vuc0RhdGEpfQopCgpleGFtcGxlRml0c0hlYXZ5IDwtIGxhcHBseSgKICBleGFtcGxlRml0c0hlYXZ5LCAKICBmdW5jdGlvbihkKSB7CiAgICBkJHNldFhtaW4ocG93ZVJsYXc6OmVzdGltYXRlX3htaW4oZCwgeG1heCA9IEluZikpCiAgICBkCiAgICB9IAopCiAgCm5hbWVzKGV4YW1wbGVGaXRzSGVhdnkpIDwtIGMoImV4cCIsICJsbm9ybSIsICJwbCIsICJ3ZWlidWxsIikKYGBgCgo8IS0tClRha2luZyBhIHF1aWNrIGxvb2sgYXQgZ29vZG5lc3Mtb2YtZml0IHN0YXRpc3RpY3MsIHdlIGFjdHVhbGx5IGZpbmQgdGhhdCB3ZSBjYW5ub3QgcmVqZWN0IGFueSBvZiB0aGUgZGlzdHJpYnV0aW9ucyBvdXQgb2YgaGFuZCAoZGVzcGl0ZSBrbm93aW5nIHRoZSB0cnV0aCBpcyBleHBvbmVudGlhbCkuCkl0IGlzIHdvcnRoIG5vdGluZyB0aGF0IHRoZSBCSUMgc2VlbXMgdG8gcHJlZGljdCB0aGUgdHJ1ZSBtb2RlbCwgYnV0IHRoZSBBSUMgZG9lcyBub3QgKHdoaWNoLCBmcm9tIHdoYXQgSSByZWNhbGwsIGlzIGV4cGVjdGVkLiBUaGUgQUlDIGlzIG1lYW50IHRvIGlkZW50aWZ5IHRoZSBiZXN0IHByZWRpY3RpdmUgbW9kZWwgcmF0aGVyIHRoYW4gdGhlIHRydWUgbW9kZWwsIGFzc3VtaW5nIHRoYXQgdGhlIHRydWUgbW9kZWwgaXMgaW4gdGhlIHNldCBvZiBtb2RlbHMgY29tcGFyZWQuIEJJQyBpcyBtZWFudCB0byBpZGVudGlmeSB0aGUgbW9kZWwgbW9zdCBsaWtlbHkgdG8gYmUgdHJ1ZSwgb24gdGhlIG90aGVyIGhhbmQpLgotLT4KCmBgYHtyLCBldmFsPUZBTFNFfQpmaXRkaXN0cnBsdXM6OmdvZnN0YXQoZXhhbXBsZUZpdHNOb3RIZWF2eSkKYGBgCgo8IS0tRHVlIHRvIGEgc2xpZ2h0bHkgZGlmZmVyZW50IG9wdGltaXNhdGlvbiBwcm9jZWR1cmUgaXQgc2VlbXMsIHRoZSBgZ2FtbHNzYCBwYWNrYWdlIGFjdHVhbGx5IHByZWZlcnMgYSBnYW1tYSBkaXN0cmlidXRpb24gZm9yIHRoZSBkYXRhLCBhbGJlaXQgd2l0aCBhIHNoYXBlIHBhcmFtZXRlciB0aGF0IGlzIG5lYXJseSAxLiAgV2UgZG8gc3VwcHJlc3Mgd2FybmluZ3MgZm9yIGFueSBvZiB0aGUgZXJyb3JzIHRoYXQgbWlnaHQgY29tZSBmcm9tIHRoZSBsYXJnZSBudW1iZXIgb2YgZGlzdHJpYnV0aW9ucyBmaXR0ZWQgYnkgdGhlIHBhY2thZ2UuIC0tPgoKYGBge3IsIHdhcm5pbmc9RkFMU0UsIGVycm9yPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBldmFsPUZBTFNFfQpxdWlldChleGFtcGxlRGF0YV9nYW1sc3MgPC0gZ2FtbHNzOjpmaXREaXN0KGV4YW1wbGVEYXRhKSkKZXhhbXBsZURhdGFfZ2FtbHNzCmBgYAoKYGBge3IsIHdhcm5pbmc9RkFMU0UsIGVycm9yPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBldmFsPUZBTFNFfQpxdWlldChjZW5zRGF0YV9nYW1sc3MgPC0gZ2FtbHNzOjpmaXREaXN0KGNlbnNEYXRhKSkKZXhhbXBsZURhdGFfZ2FtbHNzCmBgYAoKPCEtLUludGVyZXN0aW5nbHksIHRoZSBgcG93ZVJsYXdgIHBhY2thZ2VzIGFsbCBpZGVudGlmeSB0aGUgJ2hlYXZ5IHRhaWwnIGFzIGJlZ2lubmluZyBmYWlybHkgZmFyIGF3YXkgZnJvbSB0aGUgYWN0dWFsIHN0YXJ0aW5nIHBvaW50IChzaW5jZSBhbGwgdGhlIGRhdGEgaXMgZWZmZWN0aXZlbHkgdGFpbCkgZXhjZXB0IGZvciB0aGUgV2VpYnVsbC4gLS0+CgpgYGB7ciwgZXZhbD1GQUxTRX0KZXhhbXBsZUZpdHNIZWF2eQpgYGAKCjwhLS0gClNpbmNlIHdlIGFyZSBub3QgdHJ5aW5nIHRvIGZpdCBhIHRhaWwgb25seSBoZXJlLCB0aGUgYHBvd2VSbGF3YCBtZXRob2RzIGFyZSBub3QgdGVjaG5pY2FsbHkgZml0IGZvciBwdXJwb3NlLCBidXQgaXQgbWlnaHQgYmUgaGVscGZ1bCBpbiB0aGUgb3RoZXIgZGF0YSBzZXRzLgpUaGUgdXN1YWwgd29ya2Zsb3cgaXMgZGV0ZXJtaW5pbmcgdGhhdCB0aGUgdGFpbCBoYXMgc29tZSBiZWhhdmlvdXIgb25lIHdpc2hlcyB0byBkZXNjcmliZSwgZm9sbG93ZWQgYnkgZml0dGluZyBzb21lIGRpc3RyaWJ1dGlvbnMsIGRldGVybWluaW5nIGlmIHRoZWlyIGZpdHMgYXJlIHJlamVjdGVkLCBhbmQgdGhlbiBjb21wYXJpbmcgdGhlbSBvdmVyIHNoYXJlZCByYW5nZXMuClRoaXMgaXMgY29tcHV0YXRpb25hbGx5IGRpZmZpY3VsdCBpbiBwcmFjdGljZSAoaW4gUiBhdCBsZWFzdCkgc28gd2UgZG8gbm90IGRvIHNvIGhlcmUuCgojIyMjIFN1Y2Nlc3NmdWwgTmV1dHJhbAoKIyMjIyBVbnN1Y2Nlc3NmdWwgTmV1dHJhbAoKIyMjIyBEZXRlY3RlZCBOb24tbmV1dHJhbAoKIyMjIyBCdXJzdGluZXNzIG9mIFN1Y2Nlc3NlcwoKLS0+CgojIyMgUGxvdHMgey50YWJzZXR9CgojIyMjIEZ1bGwgeCBSYW5nZSB7LnRhYnNldH0KCiMjIyMjIEFsbCBFdmVudHMsIEJ5IE51bWJlciBpbiBTZXF1ZW5jZSwgVGltZSBieSBFbnZpcm9ubWVudAoKYGBge3IsIHdhcm5pbmc9RkFMU0V9CmdncGxvdDI6OmdncGxvdCgKICAgIEV2ZW50cyAlPiUgZHBseXI6OmZpbHRlcigKICAgICAgICBTcGFjZSAhPSAiUmluZyIKICAgICksCiAgICBnZ3Bsb3QyOjphZXMoCiAgICAgICAgeCA9IEludGVyYXJyaXZhbFRpbWUsCiAgICAgICAgZmlsbCA9IGZhY3RvcihFdmVudEluU2VxdWVuY2UpCiAgICApCikgKyBnZ3Bsb3QyOjpnZW9tX2RlbnNpdHkoCiAgYWxwaGEgPSAwLjI1CikgKyBnZ3Bsb3QyOjpzY2FsZV9maWxsX3ZpcmlkaXNfZCgKICAiRXZlbnQgIyIKKSArIGdncGxvdDI6OmZhY2V0X2dyaWQoCiAgICBNb2RpZmllciArIE1vZEludGVuc2l0eSB+IFNwYWNlICsgRGlzdGFuY2UKKSArIGdncGxvdDI6OnNjYWxlX3hfbG9nMTAoKSAjLT4gZW52aXJvbm1lbnRldmVudHNzZXF1ZW5jZQojIGdncGxvdDI6Omdnc2F2ZShlbnZpcm9ubWVudGV2ZW50c3NlcXVlbmNlLCBmaWxlbmFtZSA9ICJNTkEtRXZlbnRFbnZpcm9ubWVudEFycml2YWxUaW1lcy1TZXF1ZW5jZS5wZGYiLCBkcGkgPSAicmV0aW5hIiwgd2lkdGggPSAxMSwgaGVpZ2h0ID0gOCkKYGBgCgojIyMjIyBBbGwgRXZlbnRzLCBCeSBOZXV0cmFsL0R5bmFtaWMsIFRpbWUgYnkgRW52aXJvbm1lbnQKCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQpnZ3Bsb3QyOjpnZ3Bsb3QoCiAgICBFdmVudHMgJT4lIGRwbHlyOjpmaWx0ZXIoCiAgICAgICAgU3BhY2UgIT0gIlJpbmciCiAgICApLAogICAgZ2dwbG90Mjo6YWVzKAogICAgICAgIHggPSBJbnRlcmFycml2YWxUaW1lLAogICAgICAgIGZpbGwgPSBOZXV0cmFsCiAgICApCikgKyBnZ3Bsb3QyOjpnZW9tX2RlbnNpdHkoCiAgYWxwaGEgPSAwLjI1CikgKyBnZ3Bsb3QyOjpzY2FsZV9maWxsX3ZpcmlkaXNfZCgKKSArIGdncGxvdDI6OmZhY2V0X2dyaWQoCiAgICBNb2RpZmllciArIE1vZEludGVuc2l0eSB+IFNwYWNlICsgRGlzdGFuY2UKKSArIGdncGxvdDI6OnNjYWxlX3hfbG9nMTAoKSAjLT4gZW52aXJvbm1lbnRldmVudHNuZXV0cmFsCiMgZ2dwbG90Mjo6Z2dzYXZlKGVudmlyb25tZW50ZXZlbnRzbmV1dHJhbCwgZmlsZW5hbWUgPSAiTU5BLUV2ZW50RW52aXJvbm1lbnRBcnJpdmFsVGltZXMtT3ZlcnZpZXcucGRmIiwgZHBpID0gInJldGluYSIsIHdpZHRoID0gMTEsIGhlaWdodCA9IDgpCmBgYAoKIyMjIyMgQWxsIEV2ZW50cywgQnkgTnVtYmVyIGluIFNlcXVlbmNlLCBPdmVyYWxsIFRpbWUKCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQpFdmVudHMgJT4lIGRwbHlyOjpncm91cF9ieSgKICAgIFNpbXVsYXRpb24sIEl0ZXIsIERpc3RhbmNlLCAKICAgIE1vZGlmaWVyLCBNb2RJbnRlbnNpdHksIEVudmlyb25tZW50cywgU3BhY2UKKSAlPiUgZHBseXI6OmFycmFuZ2UoCiAgICBUaW1lcwopICU+JSBkcGx5cjo6bXV0YXRlKAogICAgSW50ZXJhcnJpdmFsVGltZSA9IFRpbWVzIC0gbGFnKFRpbWVzKSwgCiAgICBEeW5hbWljID0gIU5ldXRyYWwsIAogICAgU2VxdWVuY2UgPSBjdW1zdW0oTmV1dHJhbCkKKSAlPiUgZHBseXI6Omdyb3VwX2J5KAogICAgRW52aXJvbm1lbnQsIFNlcXVlbmNlCikgJT4lIGRwbHlyOjptdXRhdGUoCiAgICBFdmVudEluU2VxdWVuY2UgPSBjdW1zdW0oRHluYW1pYykKKSAlPiUgZHBseXI6OmZpbHRlcigKICAgIFNwYWNlICE9ICJSaW5nIgopICU+JSBnZ3Bsb3QyOjpnZ3Bsb3QoZ2dwbG90Mjo6YWVzKAogICAgeCA9IEludGVyYXJyaXZhbFRpbWUsCiAgICBmaWxsID0gZmFjdG9yKEV2ZW50SW5TZXF1ZW5jZSkKKQopICsgZ2dwbG90Mjo6Z2VvbV9kZW5zaXR5KAogICAgYWxwaGEgPSAwLjI1CikgKyBnZ3Bsb3QyOjpzY2FsZV9maWxsX3ZpcmlkaXNfZCgKICAiRXZlbnQgIyIKKSArIGdncGxvdDI6OmZhY2V0X2dyaWQoCiAgICBNb2RpZmllciArIE1vZEludGVuc2l0eSB+IFNwYWNlICsgRGlzdGFuY2UKKSArIGdncGxvdDI6OnNjYWxlX3hfbG9nMTAoKSArIGdncGxvdDI6OmNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLCAyKSkgIyAtPiBvdmVyYWxsZXZlbnRzc2VxdWVuY2UKIyBnZ3Bsb3QyOjpnZ3NhdmUob3ZlcmFsbGV2ZW50c3NlcXVlbmNlLCBmaWxlbmFtZSA9ICJNTkEtRXZlbnRPdmVyYWxsQXJyaXZhbFRpbWVzLVNlcXVlbmNlLnBkZiIsIGRwaSA9ICJyZXRpbmEiLCB3aWR0aCA9IDExLCBoZWlnaHQgPSA4KQpgYGAKCiMjIyMjIEFsbCBFdmVudHMsIEJ5IE5ldXRyYWwvRHluYW1pY3MsIE92ZXJhbGwgVGltZQoKYGBge3IsIHdhcm5pbmc9RkFMU0V9CkV2ZW50cyAlPiUgZHBseXI6Omdyb3VwX2J5KAogICAgU2ltdWxhdGlvbiwgSXRlciwgRGlzdGFuY2UsIAogICAgTW9kaWZpZXIsIE1vZEludGVuc2l0eSwgRW52aXJvbm1lbnRzLCBTcGFjZQopICU+JSBkcGx5cjo6YXJyYW5nZSgKICAgIFRpbWVzCikgJT4lIGRwbHlyOjptdXRhdGUoCiAgICBJbnRlcmFycml2YWxUaW1lID0gVGltZXMgLSBsYWcoVGltZXMpLCAKICAgIER5bmFtaWMgPSAhTmV1dHJhbCwgCiAgICBTZXF1ZW5jZSA9IGN1bXN1bShOZXV0cmFsKQopICU+JSBkcGx5cjo6Z3JvdXBfYnkoCiAgICBFbnZpcm9ubWVudCwgU2VxdWVuY2UKKSAlPiUgZHBseXI6Om11dGF0ZSgKICAgIEV2ZW50SW5TZXF1ZW5jZSA9IGN1bXN1bShEeW5hbWljKQopICU+JSBkcGx5cjo6ZmlsdGVyKAogICAgU3BhY2UgIT0gIlJpbmciCikgJT4lIGdncGxvdDI6OmdncGxvdChnZ3Bsb3QyOjphZXMoCiAgICB4ID0gSW50ZXJhcnJpdmFsVGltZSwKICAgIGZpbGwgPSBOZXV0cmFsCikKKSArIGdncGxvdDI6Omdlb21fZGVuc2l0eSgKICAgIGFscGhhID0gMC4yNQopICsgZ2dwbG90Mjo6c2NhbGVfZmlsbF92aXJpZGlzX2QoCikgKyBnZ3Bsb3QyOjpmYWNldF9ncmlkKAogICAgTW9kaWZpZXIgKyBNb2RJbnRlbnNpdHkgfiBTcGFjZSArIERpc3RhbmNlCikgKyBnZ3Bsb3QyOjpzY2FsZV94X2xvZzEwKCkgIyAtPiBvdmVyYWxsZXZlbnRzbmV1dHJhbAojIGdncGxvdDI6Omdnc2F2ZShvdmVyYWxsZXZlbnRzbmV1dHJhbCwgZmlsZW5hbWUgPSAiTU5BLUV2ZW50T3ZlcmFsbEFycml2YWxUaW1lcy1PdmVydmlldy5wZGYiLCBkcGkgPSAicmV0aW5hIiwgd2lkdGggPSAxMSwgaGVpZ2h0ID0gOCkKYGBgCgojIyMjIyBTdWNjZXNzZnVsIEV2ZW50cywgQnkgTnVtYmVyIGluIFNlcXVlbmNlLCBUaW1lIGJ5IEVudmlyb25tZW50CgpgYGB7ciwgd2FybmluZz1GQUxTRX0KZ2dwbG90Mjo6Z2dwbG90KAogICAgRXZlbnRzU3VjY2Vzc2VzICU+JSBkcGx5cjo6ZmlsdGVyKAogICAgICAgIFNwYWNlICE9ICJSaW5nIgogICAgKSwKICAgIGdncGxvdDI6OmFlcygKICAgICAgICB4ID0gSW50ZXJhcnJpdmFsVGltZSwKICAgICAgICBmaWxsID0gZmFjdG9yKEV2ZW50SW5TZXF1ZW5jZSkKICAgICkKKSArIGdncGxvdDI6Omdlb21fZGVuc2l0eSgKICBhbHBoYSA9IDAuMjUKKSArIGdncGxvdDI6OnNjYWxlX2ZpbGxfdmlyaWRpc19kKAogICJFdmVudCAjIgopICsgZ2dwbG90Mjo6ZmFjZXRfZ3JpZCgKICAgIE1vZGlmaWVyICsgTW9kSW50ZW5zaXR5IH4gU3BhY2UgKyBEaXN0YW5jZQopICsgZ2dwbG90Mjo6c2NhbGVfeF9sb2cxMCgKKSArIGdncGxvdDI6OmNvb3JkX2NhcnRlc2lhbigKICB5bGltID0gYygwLCAyKQopICMtPiBlbnZpcm9ubWVudGV2ZW50c3N1Y2Nlc3NzZXF1ZW5jZQojIGdncGxvdDI6Omdnc2F2ZShlbnZpcm9ubWVudGV2ZW50c3N1Y2Nlc3NzZXF1ZW5jZSwgZmlsZW5hbWUgPSAiTU5BLUV2ZW50U3VjY2Vzc0Vudmlyb25tZW50QXJyaXZhbFRpbWVzLVNlcXVlbmNlLnBkZiIsIGRwaSA9ICJyZXRpbmEiLCB3aWR0aCA9IDExLCBoZWlnaHQgPSA4KQpgYGAKCiMjIyMjIFN1Y2Nlc3NmdWwgRXZlbnRzLCBCeSBOZXV0cmFsL0R5bmFtaWNzLCBUaW1lIGJ5IEVudmlyb25tZW50CgpgYGB7ciwgd2FybmluZz1GQUxTRX0KZ2dwbG90Mjo6Z2dwbG90KAogICAgRXZlbnRzU3VjY2Vzc2VzICU+JSBkcGx5cjo6ZmlsdGVyKAogICAgICAgIFNwYWNlICE9ICJSaW5nIgogICAgKSwKICAgIGdncGxvdDI6OmFlcygKICAgICAgICB4ID0gSW50ZXJhcnJpdmFsVGltZSwKICAgICAgICBmaWxsID0gTmV1dHJhbAogICAgKQopICsgZ2dwbG90Mjo6Z2VvbV9kZW5zaXR5KAogIGFscGhhID0gMC4yNQopICsgZ2dwbG90Mjo6c2NhbGVfZmlsbF92aXJpZGlzX2QoCikgKyBnZ3Bsb3QyOjpmYWNldF9ncmlkKAogICAgTW9kaWZpZXIgKyBNb2RJbnRlbnNpdHkgfiBTcGFjZSArIERpc3RhbmNlCikgKyBnZ3Bsb3QyOjpzY2FsZV94X2xvZzEwKCkgIy0+IGVudmlyb25tZW50ZXZlbnRzc3VjY2Vzc25ldXRyYWwKIyBnZ3Bsb3QyOjpnZ3NhdmUoZW52aXJvbm1lbnRldmVudHNzdWNjZXNzbmV1dHJhbCwgZmlsZW5hbWUgPSAiTU5BLUV2ZW50U3VjY2Vzc0Vudmlyb25tZW50QXJyaXZhbFRpbWVzLU92ZXJ2aWV3LnBkZiIsIGRwaSA9ICJyZXRpbmEiLCB3aWR0aCA9IDExLCBoZWlnaHQgPSA4KQpgYGAKCiMjIyMjIFN1Y2Nlc3NmdWwgRXZlbnRzLCBCeSBOdW1iZXIgaW4gU2VxdWVuY2UsIE92ZXJhbGwgVGltZQoKYGBge3IsIHdhcm5pbmc9RkFMU0V9CkV2ZW50c1N1Y2Nlc3NlcyAlPiUgZHBseXI6Omdyb3VwX2J5KAogICAgU2ltdWxhdGlvbiwgSXRlciwgRGlzdGFuY2UsIAogICAgTW9kaWZpZXIsIE1vZEludGVuc2l0eSwgRW52aXJvbm1lbnRzLCBTcGFjZQopICU+JSBkcGx5cjo6YXJyYW5nZSgKICAgIFRpbWVzCikgJT4lIGRwbHlyOjptdXRhdGUoCiAgICBJbnRlcmFycml2YWxUaW1lID0gVGltZXMgLSBsYWcoVGltZXMpLCAKICAgIER5bmFtaWMgPSAhTmV1dHJhbCwgCiAgICBTZXF1ZW5jZSA9IGN1bXN1bShOZXV0cmFsKQopICU+JSBkcGx5cjo6Z3JvdXBfYnkoCiAgICBFbnZpcm9ubWVudCwgU2VxdWVuY2UKKSAlPiUgZHBseXI6Om11dGF0ZSgKICAgIEV2ZW50SW5TZXF1ZW5jZSA9IGN1bXN1bShEeW5hbWljKQopICU+JSBkcGx5cjo6ZmlsdGVyKAogICAgU3BhY2UgIT0gIlJpbmciCikgJT4lIGdncGxvdDI6OmdncGxvdChnZ3Bsb3QyOjphZXMoCiAgICB4ID0gSW50ZXJhcnJpdmFsVGltZSwKICAgIGZpbGwgPSBmYWN0b3IoRXZlbnRJblNlcXVlbmNlKQopCikgKyBnZ3Bsb3QyOjpnZW9tX2RlbnNpdHkoCiAgICBhbHBoYSA9IDAuMjUKKSArIGdncGxvdDI6OnNjYWxlX2ZpbGxfdmlyaWRpc19kKAogICJFdmVudCAjIgopICsgZ2dwbG90Mjo6ZmFjZXRfZ3JpZCgKICAgIE1vZGlmaWVyICsgTW9kSW50ZW5zaXR5IH4gU3BhY2UgKyBEaXN0YW5jZQopICsgZ2dwbG90Mjo6c2NhbGVfeF9sb2cxMCgpICsgZ2dwbG90Mjo6Y29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDAsIDIpKSAjIC0+IG92ZXJhbGxldmVudHNzdWNjZXNzc2VxdWVuY2UKIyBnZ3Bsb3QyOjpnZ3NhdmUob3ZlcmFsbGV2ZW50c3N1Y2Nlc3NzZXF1ZW5jZSwgZmlsZW5hbWUgPSAiTU5BLUV2ZW50U3VjY2Vzc092ZXJhbGxBcnJpdmFsVGltZXMtU2VxdWVuY2UucGRmIiwgZHBpID0gInJldGluYSIsIHdpZHRoID0gMTEsIGhlaWdodCA9IDgpCmBgYAoKIyMjIyMgU3VjY2Vzc2Z1bCBFdmVudHMsIEJ5IE5ldXRyYWwvRHluYW1pY3MsIE92ZXJhbGwgVGltZQoKYGBge3IsIHdhcm5pbmc9RkFMU0V9CkV2ZW50c1N1Y2Nlc3NlcyAlPiUgZHBseXI6Omdyb3VwX2J5KAogICAgU2ltdWxhdGlvbiwgSXRlciwgRGlzdGFuY2UsIAogICAgTW9kaWZpZXIsIE1vZEludGVuc2l0eSwgRW52aXJvbm1lbnRzLCBTcGFjZQopICU+JSBkcGx5cjo6YXJyYW5nZSgKICAgIFRpbWVzCikgJT4lIGRwbHlyOjptdXRhdGUoCiAgICBJbnRlcmFycml2YWxUaW1lID0gVGltZXMgLSBsYWcoVGltZXMpLCAKICAgIER5bmFtaWMgPSAhTmV1dHJhbCwgCiAgICBTZXF1ZW5jZSA9IGN1bXN1bShOZXV0cmFsKQopICU+JSBkcGx5cjo6Z3JvdXBfYnkoCiAgICBFbnZpcm9ubWVudCwgU2VxdWVuY2UKKSAlPiUgZHBseXI6Om11dGF0ZSgKICAgIEV2ZW50SW5TZXF1ZW5jZSA9IGN1bXN1bShEeW5hbWljKQopICU+JSBkcGx5cjo6ZmlsdGVyKAogICAgU3BhY2UgIT0gIlJpbmciCikgJT4lIGdncGxvdDI6OmdncGxvdChnZ3Bsb3QyOjphZXMoCiAgICB4ID0gSW50ZXJhcnJpdmFsVGltZSwKICAgIGZpbGwgPSBOZXV0cmFsCikKKSArIGdncGxvdDI6Omdlb21fZGVuc2l0eSgKICAgIGFscGhhID0gMC4yNQopICsgZ2dwbG90Mjo6c2NhbGVfZmlsbF92aXJpZGlzX2QoCikgKyBnZ3Bsb3QyOjpmYWNldF9ncmlkKAogICAgTW9kaWZpZXIgKyBNb2RJbnRlbnNpdHkgfiBTcGFjZSArIERpc3RhbmNlCikgKyBnZ3Bsb3QyOjpzY2FsZV94X2xvZzEwKCkgIyAtPiBvdmVyYWxsZXZlbnRzc3VjY2Vzc25ldXRyYWwKIyBnZ3Bsb3QyOjpnZ3NhdmUob3ZlcmFsbGV2ZW50c3N1Y2Nlc3NuZXV0cmFsLCBmaWxlbmFtZSA9ICJNTkEtRXZlbnRTdWNjZXNzT3ZlcmFsbEFycml2YWxUaW1lcy1PdmVydmlldy5wZGYiLCBkcGkgPSAicmV0aW5hIiwgd2lkdGggPSAxMSwgaGVpZ2h0ID0gOCkKYGBgCgojIyMjIFRydW5jLiB4IFJhbmdlIHsudGFic2V0fQoKIyMjIyMgQWxsIEV2ZW50cywgQnkgTnVtYmVyIGluIFNlcXVlbmNlLCBUaW1lIGJ5IEVudmlyb25tZW50CgpgYGB7ciwgd2FybmluZz1GQUxTRX0KZ2dwbG90Mjo6Z2dwbG90KAogICAgRXZlbnRzICU+JSBkcGx5cjo6ZmlsdGVyKAogICAgICAgIFNwYWNlICE9ICJSaW5nIgogICAgKSwKICAgIGdncGxvdDI6OmFlcygKICAgICAgICB4ID0gSW50ZXJhcnJpdmFsVGltZSwKICAgICAgICBmaWxsID0gZmFjdG9yKEV2ZW50SW5TZXF1ZW5jZSkKICAgICkKKSArIGdncGxvdDI6Omdlb21fZGVuc2l0eSgKICBhbHBoYSA9IDAuMjUKKSArIGdncGxvdDI6OnNjYWxlX2ZpbGxfdmlyaWRpc19kKAogICJFdmVudCAjIgopICsgZ2dwbG90Mjo6ZmFjZXRfZ3JpZCgKICAgIE1vZGlmaWVyICsgTW9kSW50ZW5zaXR5IH4gU3BhY2UgKyBEaXN0YW5jZQopICsgZ2dwbG90Mjo6c2NhbGVfeF9sb2cxMCgKKSArIGdncGxvdDI6OmNvb3JkX2NhcnRlc2lhbigKICB4bGltID0gYygxZS0xLCAxZTQpCikgIy0+IGVudmlyb25tZW50ZXZlbnRzc2VxdWVuY2UKIyBnZ3Bsb3QyOjpnZ3NhdmUoZW52aXJvbm1lbnRldmVudHNzZXF1ZW5jZSwgZmlsZW5hbWUgPSAiTU5BLUV2ZW50RW52aXJvbm1lbnRBcnJpdmFsVGltZXMtU2VxdWVuY2UucGRmIiwgZHBpID0gInJldGluYSIsIHdpZHRoID0gMTEsIGhlaWdodCA9IDgpCmBgYAoKCiMjIyMjIEFsbCBFdmVudHMsIEJ5IE5ldXRyYWwvRHluYW1pYywgVGltZSBieSBFbnZpcm9ubWVudAoKYGBge3IsIHdhcm5pbmc9RkFMU0V9CmdncGxvdDI6OmdncGxvdCgKICAgIEV2ZW50cyAlPiUgZHBseXI6OmZpbHRlcigKICAgICAgICBTcGFjZSAhPSAiUmluZyIKICAgICksCiAgICBnZ3Bsb3QyOjphZXMoCiAgICAgICAgeCA9IEludGVyYXJyaXZhbFRpbWUsCiAgICAgICAgZmlsbCA9IE5ldXRyYWwKICAgICkKKSArIGdncGxvdDI6Omdlb21fZGVuc2l0eSgKICBhbHBoYSA9IDAuMjUKKSArIGdncGxvdDI6OnNjYWxlX2ZpbGxfdmlyaWRpc19kKAopICsgZ2dwbG90Mjo6ZmFjZXRfZ3JpZCgKICAgIE1vZGlmaWVyICsgTW9kSW50ZW5zaXR5IH4gU3BhY2UgKyBEaXN0YW5jZQopICsgZ2dwbG90Mjo6c2NhbGVfeF9sb2cxMCgKKSArIGdncGxvdDI6OmNvb3JkX2NhcnRlc2lhbigKICB4bGltID0gYygxZS0xLCAxZTQpCikgIy0+IGVudmlyb25tZW50ZXZlbnRzbmV1dHJhbAojIGdncGxvdDI6Omdnc2F2ZShlbnZpcm9ubWVudGV2ZW50c25ldXRyYWwsIGZpbGVuYW1lID0gIk1OQS1FdmVudEVudmlyb25tZW50QXJyaXZhbFRpbWVzLU92ZXJ2aWV3LnBkZiIsIGRwaSA9ICJyZXRpbmEiLCB3aWR0aCA9IDExLCBoZWlnaHQgPSA4KQpgYGAKCgojIyMjIyBBbGwgRXZlbnRzLCBCeSBOdW1iZXIgaW4gU2VxdWVuY2UsIE92ZXJhbGwgVGltZQoKYGBge3IsIHdhcm5pbmc9RkFMU0V9CkV2ZW50cyAlPiUgZHBseXI6Omdyb3VwX2J5KAogICAgU2ltdWxhdGlvbiwgSXRlciwgRGlzdGFuY2UsIAogICAgTW9kaWZpZXIsIE1vZEludGVuc2l0eSwgRW52aXJvbm1lbnRzLCBTcGFjZQopICU+JSBkcGx5cjo6YXJyYW5nZSgKICAgIFRpbWVzCikgJT4lIGRwbHlyOjptdXRhdGUoCiAgICBJbnRlcmFycml2YWxUaW1lID0gVGltZXMgLSBsYWcoVGltZXMpLCAKICAgIER5bmFtaWMgPSAhTmV1dHJhbCwgCiAgICBTZXF1ZW5jZSA9IGN1bXN1bShOZXV0cmFsKQopICU+JSBkcGx5cjo6Z3JvdXBfYnkoCiAgICBFbnZpcm9ubWVudCwgU2VxdWVuY2UKKSAlPiUgZHBseXI6Om11dGF0ZSgKICAgIEV2ZW50SW5TZXF1ZW5jZSA9IGN1bXN1bShEeW5hbWljKQopICU+JSBkcGx5cjo6ZmlsdGVyKAogICAgU3BhY2UgIT0gIlJpbmciCikgJT4lIGdncGxvdDI6OmdncGxvdChnZ3Bsb3QyOjphZXMoCiAgICB4ID0gSW50ZXJhcnJpdmFsVGltZSwKICAgIGZpbGwgPSBmYWN0b3IoRXZlbnRJblNlcXVlbmNlKQopCikgKyBnZ3Bsb3QyOjpnZW9tX2RlbnNpdHkoCiAgICBhbHBoYSA9IDAuMjUKKSArIGdncGxvdDI6OnNjYWxlX2ZpbGxfdmlyaWRpc19kKAogICJFdmVudCAjIgopICsgZ2dwbG90Mjo6ZmFjZXRfZ3JpZCgKICAgIE1vZGlmaWVyICsgTW9kSW50ZW5zaXR5IH4gU3BhY2UgKyBEaXN0YW5jZQopICsgZ2dwbG90Mjo6c2NhbGVfeF9sb2cxMCgKKSArIGdncGxvdDI6OmNvb3JkX2NhcnRlc2lhbigKICB4bGltID0gYygxZS0xLCAxZTQpLAogIHlsaW0gPSBjKDAsIDIpCikgIyAtPiBvdmVyYWxsZXZlbnRzc2VxdWVuY2UKIyBnZ3Bsb3QyOjpnZ3NhdmUob3ZlcmFsbGV2ZW50c3NlcXVlbmNlLCBmaWxlbmFtZSA9ICJNTkEtRXZlbnRPdmVyYWxsQXJyaXZhbFRpbWVzLVNlcXVlbmNlLnBkZiIsIGRwaSA9ICJyZXRpbmEiLCB3aWR0aCA9IDExLCBoZWlnaHQgPSA4KQpgYGAKCiMjIyMjIEFsbCBFdmVudHMsIEJ5IE5ldXRyYWwvRHluYW1pY3MsIE92ZXJhbGwgVGltZQoKYGBge3IsIHdhcm5pbmc9RkFMU0V9CkV2ZW50cyAlPiUgZHBseXI6Omdyb3VwX2J5KAogICAgU2ltdWxhdGlvbiwgSXRlciwgRGlzdGFuY2UsIAogICAgTW9kaWZpZXIsIE1vZEludGVuc2l0eSwgRW52aXJvbm1lbnRzLCBTcGFjZQopICU+JSBkcGx5cjo6YXJyYW5nZSgKICAgIFRpbWVzCikgJT4lIGRwbHlyOjptdXRhdGUoCiAgICBJbnRlcmFycml2YWxUaW1lID0gVGltZXMgLSBsYWcoVGltZXMpLCAKICAgIER5bmFtaWMgPSAhTmV1dHJhbCwgCiAgICBTZXF1ZW5jZSA9IGN1bXN1bShOZXV0cmFsKQopICU+JSBkcGx5cjo6Z3JvdXBfYnkoCiAgICBFbnZpcm9ubWVudCwgU2VxdWVuY2UKKSAlPiUgZHBseXI6Om11dGF0ZSgKICAgIEV2ZW50SW5TZXF1ZW5jZSA9IGN1bXN1bShEeW5hbWljKQopICU+JSBkcGx5cjo6ZmlsdGVyKAogICAgU3BhY2UgIT0gIlJpbmciCikgJT4lIGdncGxvdDI6OmdncGxvdChnZ3Bsb3QyOjphZXMoCiAgICB4ID0gSW50ZXJhcnJpdmFsVGltZSwKICAgIGZpbGwgPSBOZXV0cmFsCikKKSArIGdncGxvdDI6Omdlb21fZGVuc2l0eSgKICAgIGFscGhhID0gMC4yNQopICsgZ2dwbG90Mjo6c2NhbGVfZmlsbF92aXJpZGlzX2QoCikgKyBnZ3Bsb3QyOjpmYWNldF9ncmlkKAogICAgTW9kaWZpZXIgKyBNb2RJbnRlbnNpdHkgfiBTcGFjZSArIERpc3RhbmNlCikgKyBnZ3Bsb3QyOjpzY2FsZV94X2xvZzEwKAopICsgZ2dwbG90Mjo6Y29vcmRfY2FydGVzaWFuKAogIHhsaW0gPSBjKDFlLTEsIDFlNCkKKSAjIC0+IG92ZXJhbGxldmVudHNuZXV0cmFsCiMgZ2dwbG90Mjo6Z2dzYXZlKG92ZXJhbGxldmVudHNuZXV0cmFsLCBmaWxlbmFtZSA9ICJNTkEtRXZlbnRPdmVyYWxsQXJyaXZhbFRpbWVzLU92ZXJ2aWV3LnBkZiIsIGRwaSA9ICJyZXRpbmEiLCB3aWR0aCA9IDExLCBoZWlnaHQgPSA4KQpgYGAKCiMjIyMjIFN1Y2Nlc3NmdWwgRXZlbnRzLCBCeSBOdW1iZXIgaW4gU2VxdWVuY2UsIFRpbWUgYnkgRW52aXJvbm1lbnQKCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQpnZ3Bsb3QyOjpnZ3Bsb3QoCiAgICBFdmVudHNTdWNjZXNzZXMgJT4lIGRwbHlyOjpmaWx0ZXIoCiAgICAgICAgU3BhY2UgIT0gIlJpbmciCiAgICApLAogICAgZ2dwbG90Mjo6YWVzKAogICAgICAgIHggPSBJbnRlcmFycml2YWxUaW1lLAogICAgICAgIGZpbGwgPSBmYWN0b3IoRXZlbnRJblNlcXVlbmNlKQogICAgKQopICsgZ2dwbG90Mjo6Z2VvbV9kZW5zaXR5KAogIGFscGhhID0gMC4yNQopICsgZ2dwbG90Mjo6c2NhbGVfZmlsbF92aXJpZGlzX2QoCiAgIkV2ZW50ICMiCikgKyBnZ3Bsb3QyOjpmYWNldF9ncmlkKAogICAgTW9kaWZpZXIgKyBNb2RJbnRlbnNpdHkgfiBTcGFjZSArIERpc3RhbmNlCikgKyBnZ3Bsb3QyOjpzY2FsZV94X2xvZzEwKAopICsgZ2dwbG90Mjo6Y29vcmRfY2FydGVzaWFuKAogIHhsaW0gPSBjKDFlLTEsIDFlNCksCiAgeWxpbSA9IGMoMCwgMikKKSAjLT4gZW52aXJvbm1lbnRldmVudHNzdWNjZXNzc2VxdWVuY2UKIyBnZ3Bsb3QyOjpnZ3NhdmUoZW52aXJvbm1lbnRldmVudHNzdWNjZXNzc2VxdWVuY2UsIGZpbGVuYW1lID0gIk1OQS1FdmVudFN1Y2Nlc3NFbnZpcm9ubWVudEFycml2YWxUaW1lcy1TZXF1ZW5jZS5wZGYiLCBkcGkgPSAicmV0aW5hIiwgd2lkdGggPSAxMSwgaGVpZ2h0ID0gOCkKYGBgCgoKIyMjIyMgU3VjY2Vzc2Z1bCBFdmVudHMsIEJ5IE5ldXRyYWwvRHluYW1pY3MsIFRpbWUgYnkgRW52aXJvbm1lbnQKCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQpnZ3Bsb3QyOjpnZ3Bsb3QoCiAgICBFdmVudHNTdWNjZXNzZXMgJT4lIGRwbHlyOjpmaWx0ZXIoCiAgICAgICAgU3BhY2UgIT0gIlJpbmciCiAgICApLAogICAgZ2dwbG90Mjo6YWVzKAogICAgICAgIHggPSBJbnRlcmFycml2YWxUaW1lLAogICAgICAgIGZpbGwgPSBOZXV0cmFsCiAgICApCikgKyBnZ3Bsb3QyOjpnZW9tX2RlbnNpdHkoCiAgYWxwaGEgPSAwLjI1CikgKyBnZ3Bsb3QyOjpzY2FsZV9maWxsX3ZpcmlkaXNfZCgKKSArIGdncGxvdDI6OmZhY2V0X2dyaWQoCiAgICBNb2RpZmllciArIE1vZEludGVuc2l0eSB+IFNwYWNlICsgRGlzdGFuY2UKKSArIGdncGxvdDI6OnNjYWxlX3hfbG9nMTAoCikgKyBnZ3Bsb3QyOjpjb29yZF9jYXJ0ZXNpYW4oCiAgeGxpbSA9IGMoMWUtMSwgMWU0KQopICMtPiBlbnZpcm9ubWVudGV2ZW50c3N1Y2Nlc3NuZXV0cmFsCiMgZ2dwbG90Mjo6Z2dzYXZlKGVudmlyb25tZW50ZXZlbnRzc3VjY2Vzc25ldXRyYWwsIGZpbGVuYW1lID0gIk1OQS1FdmVudFN1Y2Nlc3NFbnZpcm9ubWVudEFycml2YWxUaW1lcy1PdmVydmlldy5wZGYiLCBkcGkgPSAicmV0aW5hIiwgd2lkdGggPSAxMSwgaGVpZ2h0ID0gOCkKYGBgCgojIyMjIyBTdWNjZXNzZnVsIEV2ZW50cywgQnkgTnVtYmVyIGluIFNlcXVlbmNlLCBPdmVyYWxsIFRpbWUKCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQpFdmVudHNTdWNjZXNzZXMgJT4lIGRwbHlyOjpncm91cF9ieSgKICAgIFNpbXVsYXRpb24sIEl0ZXIsIERpc3RhbmNlLCAKICAgIE1vZGlmaWVyLCBNb2RJbnRlbnNpdHksIEVudmlyb25tZW50cywgU3BhY2UKKSAlPiUgZHBseXI6OmFycmFuZ2UoCiAgICBUaW1lcwopICU+JSBkcGx5cjo6bXV0YXRlKAogICAgSW50ZXJhcnJpdmFsVGltZSA9IFRpbWVzIC0gbGFnKFRpbWVzKSwgCiAgICBEeW5hbWljID0gIU5ldXRyYWwsIAogICAgU2VxdWVuY2UgPSBjdW1zdW0oTmV1dHJhbCkKKSAlPiUgZHBseXI6Omdyb3VwX2J5KAogICAgRW52aXJvbm1lbnQsIFNlcXVlbmNlCikgJT4lIGRwbHlyOjptdXRhdGUoCiAgICBFdmVudEluU2VxdWVuY2UgPSBjdW1zdW0oRHluYW1pYykKKSAlPiUgZHBseXI6OmZpbHRlcigKICAgIFNwYWNlICE9ICJSaW5nIgopICU+JSBnZ3Bsb3QyOjpnZ3Bsb3QoZ2dwbG90Mjo6YWVzKAogICAgeCA9IEludGVyYXJyaXZhbFRpbWUsCiAgICBmaWxsID0gZmFjdG9yKEV2ZW50SW5TZXF1ZW5jZSkKKQopICsgZ2dwbG90Mjo6Z2VvbV9kZW5zaXR5KAogICAgYWxwaGEgPSAwLjI1CikgKyBnZ3Bsb3QyOjpzY2FsZV9maWxsX3ZpcmlkaXNfZCgKICAiRXZlbnQgIyIKKSArIGdncGxvdDI6OmZhY2V0X2dyaWQoCiAgICBNb2RpZmllciArIE1vZEludGVuc2l0eSB+IFNwYWNlICsgRGlzdGFuY2UKKSArIGdncGxvdDI6OnNjYWxlX3hfbG9nMTAoCikgKyBnZ3Bsb3QyOjpjb29yZF9jYXJ0ZXNpYW4oCiAgeGxpbSA9IGMoMWUtMSwgMWU0KSwKICB5bGltID0gYygwLCAyKQopICMgLT4gb3ZlcmFsbGV2ZW50c3N1Y2Nlc3NzZXF1ZW5jZQojIGdncGxvdDI6Omdnc2F2ZShvdmVyYWxsZXZlbnRzc3VjY2Vzc3NlcXVlbmNlLCBmaWxlbmFtZSA9ICJNTkEtRXZlbnRTdWNjZXNzT3ZlcmFsbEFycml2YWxUaW1lcy1TZXF1ZW5jZS5wZGYiLCBkcGkgPSAicmV0aW5hIiwgd2lkdGggPSAxMSwgaGVpZ2h0ID0gOCkKYGBgCgoKIyMjIyMgU3VjY2Vzc2Z1bCBFdmVudHMsIEJ5IE5ldXRyYWwvRHluYW1pY3MsIE92ZXJhbGwgVGltZQoKYGBge3Isd2FybmluZz1GQUxTRX0KRXZlbnRzU3VjY2Vzc2VzICU+JSBkcGx5cjo6Z3JvdXBfYnkoCiAgICBTaW11bGF0aW9uLCBJdGVyLCBEaXN0YW5jZSwgCiAgICBNb2RpZmllciwgTW9kSW50ZW5zaXR5LCBFbnZpcm9ubWVudHMsIFNwYWNlCikgJT4lIGRwbHlyOjphcnJhbmdlKAogICAgVGltZXMKKSAlPiUgZHBseXI6Om11dGF0ZSgKICAgIEludGVyYXJyaXZhbFRpbWUgPSBUaW1lcyAtIGxhZyhUaW1lcyksIAogICAgRHluYW1pYyA9ICFOZXV0cmFsLCAKICAgIFNlcXVlbmNlID0gY3Vtc3VtKE5ldXRyYWwpCikgJT4lIGRwbHlyOjpncm91cF9ieSgKICAgIEVudmlyb25tZW50LCBTZXF1ZW5jZQopICU+JSBkcGx5cjo6bXV0YXRlKAogICAgRXZlbnRJblNlcXVlbmNlID0gY3Vtc3VtKER5bmFtaWMpCikgJT4lIGRwbHlyOjpmaWx0ZXIoCiAgICBTcGFjZSAhPSAiUmluZyIKKSAlPiUgZ2dwbG90Mjo6Z2dwbG90KGdncGxvdDI6OmFlcygKICAgIHggPSBJbnRlcmFycml2YWxUaW1lLAogICAgZmlsbCA9IE5ldXRyYWwKKQopICsgZ2dwbG90Mjo6Z2VvbV9kZW5zaXR5KAogICAgYWxwaGEgPSAwLjI1CikgKyBnZ3Bsb3QyOjpzY2FsZV9maWxsX3ZpcmlkaXNfZCgKKSArIGdncGxvdDI6OmZhY2V0X2dyaWQoCiAgICBNb2RpZmllciArIE1vZEludGVuc2l0eSB+IFNwYWNlICsgRGlzdGFuY2UKKSArIGdncGxvdDI6OnNjYWxlX3hfbG9nMTAoCikgKyBnZ3Bsb3QyOjpjb29yZF9jYXJ0ZXNpYW4oCiAgeGxpbSA9IGMoMWUtMSwgMWU0KQopICMgLT4gb3ZlcmFsbGV2ZW50c3N1Y2Nlc3NuZXV0cmFsCiMgZ2dwbG90Mjo6Z2dzYXZlKG92ZXJhbGxldmVudHNzdWNjZXNzbmV1dHJhbCwgZmlsZW5hbWUgPSAiTU5BLUV2ZW50U3VjY2Vzc092ZXJhbGxBcnJpdmFsVGltZXMtT3ZlcnZpZXcucGRmIiwgZHBpID0gInJldGluYSIsIHdpZHRoID0gMTEsIGhlaWdodCA9IDgpCmBgYAo=